算法导论第三版第8章思考题

8-1

a.

因为对于每一种输入,不可能能够到达同一片叶子,所以一共有 n! 片子是可以到达的。其次因为输入完全随机,每种输入概率相等且到叶子结点的路径是固定的,这 n! 个叶子结点的概率也是相等的,为 1n!

b.

一共有 k 个叶子节点,那么一定会有 k 条从叶子节点到根结点的路径,所有的路径要么会经过 T 的左孩子节点,要么经过它的右孩子节点,即所有 k 条路径都会从 T 的左孩子节点或右孩子节点出发。然后这 k 条路径从根节点到它的左右孩子节点的路径长度总和为 k ,所以有

D(T)=D(LT)+D(RT)+k

c.

题目里面都已经说得很明显了,直接按题目和b小问里的结论就可以得出了。

d.

我们令 f(i)=ilgi+(ki)lg(ki) ,将 f(i) i 进行求导得到 f(i)=lgi+1lg(ki)1=lgiki 。令 f(i)=0 可以解得 i=k2 ,而且因为 f′′(k2)=4k0 ,所以 f(i) i=k/2 处取得最小值。
所以 d(k)=2k2lgk2+k=klgk+(lg21)k=Ω(klgk)

e.

有a小问可知,一共会有 n! 个叶子,所以再有d小问知, D(TA)=Ω(n!lg(n!)) 。一共有 n! 条路径,即 n! 种排序情况,因为输入序列等概随机,所以平均时间代价为 E(T)=D(TA)n!=Ω(lg(n!))=Ω(nlgn)

f.

不会。。。

8-2

a.

计数排序。

b.

因为关键字为0或1,所以我们可以直接遍历整个数组,将每个元素与0比较,等于零的往前面放就可以了:

SORT(A)
1 i = 0
2 for j = 1 to A.length
3   if A[j] == 0
4     i = i + 1
5     exchange A[i] with A[j]

该算法不是稳定的。

c.

插入排序,堆排序和快速排序都可以。

d.

计数排序可以,因为它是稳定的而且时间复杂度为 O(n) 。b中算法不是稳定的,所以不行。c中算法时间复杂度都不是 O(n) ,所以不行。

e.

算法为:

LINEAR_IN_PLACE(A, k)
1  let C[0..k] and P[0..k] be two new arrays
2  for i = 0 to k
3    C[i] = 0
4  for j = 1 to A.length
5    C[A[j]] = C[A[j]] + 1
6  for i = 1 to k
7    C[i] = C[i] + C[i - 1]
8  copy C to P
9  j = 0
10 while j <= A.length
11   bool placed;
12   if A[j] == 1
13     placed = j < P[A[j]]
14   else placed j >= P[A[j] - 1] and j < P[A[j]]
15   if placed == true
16     j++
17   else exchange A[j] with A[C[A[j]]]
18     C[A[j]] = C[A[j]] - 1

因为算法中数组下标是从1开始的,所以与实现代码有一定的不相同。该算法是不稳定的。
java代码如下:

    /**
     * 线性时间内的原址排序
     * @param A
     * @param k
     */
    public static void Linear_in_Place(int[] A, int k){
        int[] C = new int[k];
        int[] P = new int[k];
        for (int i = 0; i < A.length; i++){
            C[A[i]] = C[A[i]] + 1;
        }
        for (int i = 1; i < C.length; i++){
            C[i] = C[i] + C[i - 1];
        }
        System.arraycopy(C, 0, P, 0, k);
        int j = 0;
        while (j < A.length){
            boolean placed;
            if (A[j] == 0){
                placed = j < P[A[j]];
            }else{
                placed = P[A[j] - 1] <= j && P[A[j]] > j;
            }
            if (placed){
                j++;
            }else{
                int c = C[A[j]] = C[A[j]] - 1;
                int temp = A[j];
                A[j] = A[c];
                A[c] = temp;
            }
        }
    }

8-3

a.

先对这些数按位数分组,然后对每个组分别进行基数排序,然后将这些组按位数从小到大连接起来。

b.

先可以找出所有字符串中的最长字符串的长度,然后将所有字符串都扩充为该长度(在后面加0)。然后从字符串最后一位开始用基数排序排列整个数组。

8-4

a.

直接对每一个红色水壶,逐一的与蓝色水壶比较直到所有的都配对成功。

b.

不会。。。

c.

1 在红色瓶中中随机选择一个,遍历所有蓝瓶找到相匹配的,并将所有蓝瓶分为比该瓶容量大和小的两组;
2 然后用上一步选出的蓝瓶与所有的红瓶比较,同样将剩下的红瓶分成比该瓶容量大和小的两组;
3 对上面两步中分得的对应的两组红瓶蓝瓶(大的对应大的,小的对应小的)重复12步,直到所有的都正确匹配。
该算法的时间复杂度为

T(n)=T(an)+T((1a)n)+Θ(n)

其中 an(1a)n 为在第1步中被分成的两组的规模。
这样就和快速排序的时间复杂度一样了,期望复杂度为 E(T)=Θ(nlgn) ,最坏情况的时间复杂度为 T(n)=Θ(n2)

8-5

a.

表示该数组是完全排序的。

b.

{2,1,4,3,6,5,8,7,10,9}

c.

i+k1j=iA[j]ki+kj=i+1A[j]ki+kj=i+1A[j]i+k1j=iA[j]k0A[i+k]A[i]k0A[i+k]A[i]

上式必须对所有 i=1,2,,nk 成立。

d.

K-SORT(A)
1 let B[1,...,n/k] and C[1,...,n] be two new array
2 for j = 1 to k
3   for i = 1 to n/k
4     B[i] = A[(j-1)*(n/k)+i-1]
5   MERGE-SORT(B)
6   for i = 0 to n/k-1
7     C[i*k + j] = B[i + 1]
8 return C

将数组从前往后分为 k 个部分,每个部分 n/k 个数,然后分别对这 n/k 个数进行归并排序,并将其至于一个新数组的从前往后间隔 k 的位置上,这样就可以保证每个位置上的数都能满足 A[i]A[i+k]
因为一共 k 个组,对每个组进行归并排序用时 O(n/klg(n/k)) ,一共用时 O(nlg(n/k)) 。该排序算法的下界为 Ω(nlgn)

e.

将整个数组分成 k 组,第 i 组数据为 A[i,k+i,,(n/k1)k+i] ,这让每组数据都是从小到大已经排序好的数组。然后按练习6.5-9中的算法对这 k 组数据合并,就可以全排序整个数组,时间复杂度为 O(nlgk)

f.

你可能感兴趣的:(算法)