第二章 算法基礎
2.1 插入排序
排序問題描述
輸入:n個數的一個序列{a1,a2,..,an}
輸出:輸入序列的一個排列{a1’,a2’,..,an’},滿足a1’<= a2’<=..<=an’.
算法描述
INSERTION-SORT(A)
1 for j = 2 to A.length
2 key = A[j]
3 //Insert A[j] into the sorted sequence A[1..j-1]
4 i = j - 1
5 while i > 0 and A[i] > key
6 A[i+1] = A[i]
7 i = i - 1
8 A[i+1] = key
算法實現
public int[] insertionSort(int[] A){
for(int j = 1; j < A.length; j++){
int key = A[j];
int i = j - 1;
while(i>0 && A[i] > key){
A[i+1] = A[i];
i--;
}
A[i+1] = key;
}
return A;
}
練習
2.1-1
2.1-2
INSERTION-SORT(A)
1 for j = 2 to A.length
2 key = A[j]
3 //Insert A[j] into the sorted sequence A[1..j-1]
4 i = j - 1
5 while i > 0 and A[i] < key
6 A[i+1] = A[i]
7 i = i - 1
8 A[i+1] = key
2.1-3
//naive search method
SEARCH(A,v)
1 for i = 1 to A.length
2 if A[i] == v
3 return i
4 return NIL
2.1-4
分析
考慮兩個1位二進制數a和b,假設它們的和c是個2位二進制數,c[1]=ab,c[2]=(a+b)/2=(a+b)>>2。
再考慮兩個2位二進制數和,它們的和是個3位二進制數;
當第一位相加時,先計算進位位c2=(a1+b1)>>1,再計算低位c1=a1^b1;
當第二位相加時,先計算進位位c3=(a2+b2+c2)>>1,再計算低位c2=a2^b2^c2
以此方法,若c1初始化爲0,則各位計算的=(an+bn+cn)>>1,cn=an^bn^cn
形式化描述
循環不變式:在循環的每次迭代開始前,c[1…i]保存着a[1…i-1]和b[1…i-1]相加的和。
證明:
初始化:在循環的第一次迭代開始前,此時i=1,c[i]=0。人爲給兩個規定——1.a[1…0]和b[1…0]不包含任何元素;2.0位二進制數相加得0。在這兩個約束下顯然c[1]保存着a[1…0]和b[1…0]相加的和。不變式成立。
保持:若循環的某次迭代開始前不變式成立,假設此時i=k,根據不變式,c[1…k]保存着a[1..k-1和]b[1..k-1]相加的和;此次迭代執行,執行的結果就是c[1…k+1]保存着a[1..k]和b[1..k]相加的和;下一次迭代開始前,此時i=k+1,由上次迭代的執行結果知c[1…k+1]保存着a[1..k]和b[1..k]相加的和,即c[1…i]保存着a[1..i-1]和b[1..i-1]相加的和。不變式成立。
終止:循環的迭代終止時,i=n+1,將循環不變式中的i替換爲n+1,即c[1…n+1]保存着a[1..n]和b[1..n]相加的和。而a[1..n]和b[1..n]就是完整的兩個二進制數,所以不變式成立。
僞代碼
ADD-BIN(A,B,C,n)
1 C[1] = 0
2 for i = 1 to n
3 C[i+1] = (A[i] + B[i] + C[i]) >> 1
4 C[i] = A[i]^B[i]^C[i]
Java代碼
public void addBin(binary[] A, binary[] B, binary[] C, int n){
C[0] = 0;
for(int i = 0; i < n; i++){
C[i+1] = (A[i] + B[i] + C[i]) >> 1;
C[i] = A[i]^B[i]^C[i];
}
}
2.2 算法分析
練習
2.2-2
僞代碼
SELECTION-SORT(A)
1 for i = 1 to A.length - 1
2 k = i
3 for j = k + 1 to A.length
4 if A[j] < A[k]
5 k = j
6 tmp = A[i]
7 A[i] = A[k]
8 A[k] = tmp
java代碼
public void selectionSort(int[] A){
for(int i = 0; i < A.length - 1; i++){
int k = i;
for(int j = k + 1; j < A.length; j++){
if(A[j] < A[k]) k = j;
}
int tmp = A[i];
A[i] = A[k];
A[k] = tmp;
}
}
形式化描述
循環不變式:A[1..i]包含A[1..n]最小數,且是已排序的。
當前n-1個排好序後,第n個既是最大數,故也是排好序的。
最佳運行時間:Θ(n^2)
最壞運行時間:Θ(n^2)
2.2-4
Modify the algorithm so it tests whether the input satisÞes some special-case con-dition and, if it does, output a pre-computed answer. The best-case running time is generally not a good measure of an algorithm.
2.3 設計算法
分治模式
1. 分解這些子問題,這些自問題是原問題的規模較小的實例.
2. 解決這些子問題,遞歸地求解這些子問題.
3. 合併這些子問題的解成原問題的解.
歸併排序
僞代碼
MERGE( A, p, q, r)
1 n1 = q − p + 1 //計算A[p..q]的長度爲n1
2 n2 = r − q //計算A[q+1..r]的長度n2
3 create arrays L[1 . . n1 + 1] and R[1 . . n2 + 1] //創建L和R兩個數組
4 for i = 1 to n1 //將A[p..q]複製到L[1..n1]
5 L[i] = A[ p + i − 1]
6 for j = 1 to n2 //將A[q+1..r]複製到R[1..n2]
7 R[j] = A[q + j]
8 L[n1 + 1] = ∞ //底部設置哨兵
9 R[n2 + 1] = ∞
10 i = 1
11 j = 1
12 for k = p to r //執行循環不變式完成兩個子數組的合併
13 if L[i] ≤ R[j]
14 A[k] = L[i]
15 i = i + 1
16 else A[k] = R[j]
17 j = j + 1
MERGE-SORT(A,p,r)
1 if p < r
2 q = p+r/2
3 MERGE-SORT(A,p,q)
4 MERGE-SORT(A,q+1,r)
5 MERGE(A,p,q,r)
java代碼
private static void merge(int[] A, int p, int q, int r){
int n1 = q - p + 1;
int n2 = r - q;
int[] L = new int[n1 + 1];
int[] R = new int[n2 + 1];
for(int i = 0; i < n1){
L[i] = A[p + i - 1];
}
for(int j = 0; j < n2; j++){
R[j] = A[q + j]
}
L[n1] = Integer.MAX_VALUE;
R[n2] = Integer.MAX_VALUE;
int i = 0;
int j = 0;
for(int k = p; k <= r; k++){
if(L[i] < R[j]) {
A[k] = L[i];
i++;
}else{
A[k] = R[j];
j++;
}
}
}
public static void mergeSort(int[] A, int p, int r){
if(p < r){
int q = (p + r)/2
mergeSort(A, p, q);
mergeSort(A, q + 1, r);
merge(A,p,q,r);
}
}
分析分治算法
練習
2.3-2
僞代碼
MERGE( A, p, q, r)
1 n1 = q − p + 1 //計算A[p..q]的長度爲n1
2 n2 = r − q //計算A[q+1..r]的長度n2
3 create arrays L[1 . . n1] and R[1 . . n2] //創建L和R兩個數組
4 for i = 1 to n1 //將A[p..q]複製到L[1..n1]
5 L[i] = A[ p + i − 1]
6 for j = 1 to n2 //將A[q+1..r]複製到R[1..n2]
7 R[j] = A[q + j]
8 i = 1
9 j = 1
10 for k = p to r //執行循環不變式完成兩個子數組的合併
11 if i < n1 and j < n2
12 if L[i] ≤ R[j]
13 A[k] = L[i]
14 i = i + 1
15 else A[k] = R[j]
16 j = j + 1
17 else break;
18 if i == n1 and j < n2
19 for j = j to n2
20 A[k++] = R[j]
21 else if j == n2 and i < n1
22 for i = i to n1
23 A[k++] = L[i]
2.3-3
The base case is when n = 2, and we have n lg n = 2 lg 2 = 2 · 1 = 2.
For the inductive step, our inductive hypothesis is that T (n/2) = (n/2)lg(n/2).
Then
T(n) = 2T(n/2) + n
= 2(n/2) lg(n/2) + n
= n(lgn − 1) + n
= nlgn − n + n
= nlgn ,
which completes the inductive proof for exact powers of 2.
2.3-4
2.3-5
二分查找僞代碼
迭代
SEARCH-BIN(A, v, low, high)
1 while low <= high
2 mid = (low+high)/2
3 if A[mid] == v
4 return mid
5 else if v > A[mid]
6 low = mid + 1
7 else high = mid - 1
8 return NIL
遞歸
SEARCH-BIN(A, v, low, high)
1 if low > high
2 return NIL
3 mid = (low+high)/2
4 if(v == A[mid])
5 return mid
6 if(v > A[mid])
7 return SEARCH-BIN(A, v, mid + 1, high)
8 else return SEARCH-BIN(A, v, low, mid - 1)
Both procedures terminate the search unsuccessfully when the range is empty (i.e.,
low > high) and terminate it successfully if the value v has been found. Based
on the comparison of v to the middle element in the searched range, the search
continues with the range halved. The recurrence for these procedures is therefore
T(n) = T(n/2) + O(1), whose solution is T(n) = (lgn).
2.3-6
The while loop of lines 5–7 of procedure I NSERTION -S ORT scans backward
through the sorted array A[1 . . j − 1] to Þnd the appropriate place for A[j]. The
hitch is that the loop not only searches for the proper place for A[ j ], but that it also moves each of the array elements that are bigger than A[ j ] one position to the right (line 6). These movements can take as much as ( j ) time, which occurs when all the j − 1 elements preceding A[ j ] are larger than A[ j ]. We can use binary search to improve the running time of the search to (lg j ), but binary search will have no effect on the running time of moving the elements. Therefore, binary search alone cannot improve the worst-case running time of I NSERTION -SORT to O(nlgn).
聲明: 本文是”算法導論第二章”學習的筆記,如果有什麼錯誤請批評指正.