第一章 引論
學習數據結構的重要性:對于大量輸入的運算性能的重要性
目錄
- 1.1 本書討論的內容
- 1.2 數學知識復習
- 1.3 遞歸簡論
- 1.4 實現泛型特性構件 pre - Java 5
- 1.5 利用Java 5泛性實現泛型特性成分
1.1 本書討論的內容
- 應用合理的算法 與 普通的算法解決問題的"差異"。
1.1.1 選擇問題
設有一組N個數而要確定其中第k個最大者。我們稱之為選擇問題。
- 方法一:
將這N個數讀進一個數組中,通過某種簡單的算法,比如冒泡排序,以遞減順序將數組排序,然后返回位置k上的元素。
/**
* 選擇問題:設有一組N個數而要確定其中第k個最大者 方法: 使用冒泡排序,然后返回位置 k-1 上的元素
*/
@Test
public void No1_1_1() {
//獲取全局變量數組的克隆數組。
int array[] = mdzz_array.clone();
int m = (int) System.currentTimeMillis();
//排序
MyUtils.sort(array);
int k = array.length / 2;
System.out.println(array[k - 1]);
//計算結束時間
int n = (int) System.currentTimeMillis();
System.out.println(n - m);
}
- 方法二:
稍微好一點的算法就可以先把前k個元素讀入數組并(以遞減的順序)進行排序。接著將剩下的元素逐個讀入,當新元素被讀到時,如果它小于等于該數組的第k個元素則忽略之,否則就將其放到數組的正確位置上。同時將數組中的一個元素擠出數組
/**
* 第二種方法 先把前k個元素讀入數組并(遞減排序).接著將剩下的元素逐個讀入。
* 當新元素被讀到時,如果它小于數組中的第k個元素則忽略之,否則將其放到數組中的正確的位置上, 同時將數組中的一個元素擠出數組。
*/
// @Test
public void No1_1_1_2() {
System.out.println("================================");
//獲取全局變量數組的克隆數組。
int array[] = mdzz_array.clone();
int n = (int) System.currentTimeMillis();
int k = array.length / 2;
//填充數組
int array_copy[] = new int[k];
for (int i = 0; i < k; i++) {
array_copy[i] = array[i];
}
//排序
MyUtils.sort(array_copy);
for (int i = k; i < array.length; i++) {
if (array[i] > array_copy[array_copy.length - 1]) {
MyUtils.insertToArray(array[i], array_copy);
}
}
//計算程序結束時間
int m = (int) System.currentTimeMillis();
//打印
System.out.println(array_copy[k - 1]);
System.out.println(m - n);
}
全局變量
static int mdzz_array[];
static {
//生成一個十萬長度的隨機數組
mdzz_array = MyUtils.upSetRandom(100000);
}
運行結果
image.png
分析
- 當數據量達到10w的時候,兩個方法都能運行出正常結果,但是方法二時間明顯小于方法一的時間
- 當數據量達到100w的時候,兩個方法都不能在短時間內運行出結果。(肯定會有更好的方法去解決,這個放到后面去講解,我暫時也沒學到233333)
1.1.2 解決流行的字謎
image.png
輸入是由一些字母構成的一個二維數組以及一組單詞組成。目標是要找出字謎中的單詞,這些單詞可能是水平的、垂直或沿對角線上任何方向放置的。
該圖,字謎是由單詞this、two、fat組成。
思路
- 通過循環,對該二維數組上的每一個點進行遍歷,八個方向開始。如果有形成單詞的,則放到答案隊列當中。
- 改進:如果我們知道字典中最小的單詞長度的話,那么我們遍歷某個點的某個方向的時候,判斷這個方向構成單詞的最大長度如果小于字典中最小單詞的長度的話。那么就可以過濾掉該方向。增加算法的效率。
代碼
本章講解思想,代碼不是很重要,所以這種篇幅過長的代碼就放到附件去了。主要是思路,思路對了代碼沒多長時間就自己敲出來了。
1.3 遞歸
程序調用自身的編程技巧稱為遞歸( recursion)。
遞歸的兩個基本準則:
- 基準情形(base case)。必須總要有某些基準的情形,他們不用遞歸就能求解。
- 不斷推進(making progress)。對于那些要遞歸求解的情形,遞歸調用必須總能朝著一個基準情形推進。
1.3.1 案例1、階乘
可能學遞歸都接觸過這個階乘問題,這個問題可能有些人都嚼爛了,隨手一打就出來了。但是,這個思想還是蠻重要的,化繁為簡。
public int jiecheng(int n){
if(n==1||n==0){
return 1;
}else{
return n * jiecheng(n-1);
}
}
(↑ 這么簡單的案例,糊弄誰呢)
1.3.2 案例2、全排列
image.png
(對不起,打擾了)
分析與思路:
-
對于這個問題,我們首先在紙上畫一畫,大家想的思路應該都是,先固定"a",然后輸出"b","c",再將"b","c"交換,之后再輸出"acb"。b,c也是先固定再讓剩下的交換。
abc.png - 那四個數呢,"abcd",一樣的,先固定a ,再 固定 b 然后輸出 abcd,交換c d,輸出 abdc 在固定a,c輸出 acbd……
實現方法:
@Test
public void No1_1_4() {
permute("xyz");
}
public void permute(String str) {
char[] c_str = str.toCharArray();
permute(c_str, 0, c_str.length - 1);
}
public void permute(char[] str, int low, int high) {
if (low == high) {
System.out.println(String.valueOf(str));
} else {
for (int i = low; i < str.length; i++) {
swap(str, low, i);
permute(str, low+1, high);
swap(str, i, low);
}
}
}
public void swap(char[]str,int i,int j){
char temp = str[i];
str[i] = str[j];
str[j] = temp;
}
總結
本章總體上來講了算法的一些優點,還有一些數學和Java的泛型基礎知識,就不在這里進行講解了。