算法導論-第二章

第二章 算法基礎

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).


聲明: 本文是”算法導論第二章”學習的筆記,如果有什麼錯誤請批評指正.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章