算法导论-第二章

第二章 算法基础

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


声明: 本文是”算法导论第二章”学习的笔记,如果有什么错误请批评指正.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值