CLRS第八章思考题

思考题8-1

a) n 个不同元素一共有 n! 种输入,每种输入的概率 1n! ,它们都对应一个可达的叶结点。

b) 当 k>1 时说明根结点 T 不是叶结点,意味着 T 的叶结点也是 LT RT 的叶结点。若 LT RT 的深度为 h ,则 LT RT 的叶结点的深度为 h+1 D(T) 必然是 D(LT) D(RT) 以及全部叶结点 k 的总和。
证明:设 dT(x) 是树 T 的结点 x 的深度。

D(T)=xleaves(T)dT(x)=xleaves(LT)dT(x)+xleaves(RT)dT(x)=xleaves(LT)(dLT(x)+1)+xleaves(RT)(dRT(x)+1)=xleaves(LT)dLT(x)+xleaves(RT)dRT(x)+xleaves(T)1=D(RT)+D(LT)+k


c) 要证明结论,只需分别证明 d(k)min1xk1{d(i)+d(ki)+k} d(k)min1xk1{d(i)+d(ki)+k} 即可。

证明 d(k)min1xk1{d(i)+d(ki)+k} ,只要证明对 i=1,2k1 d(k)d(i)+d(ki)+k 。我们拿走 T k 个叶子结点,则 D(T)=d(k) ,此时剩下 LT RT 。他们各自构成一棵树,设 RT 的叶结点为 i LT 的叶结点为 ki 有:

d(k)=D(T)=D(LT)+D(RT)+kd(i)+d(ki)+k(dD(T))

证明 d(k)min1xk1{d(i)+d(ki)+k} ,只要证明对 i=1,2k1 d(k)d(i)+d(ki)+k 。对任意 i 属于 1 k 可以找到有 i 个叶结点的 RT ki 个叶结点的 LT ,且 D(RT)=d(i)D(LT)=d(ki) 。分别构建树 T,LT,RT 有:
d(k)D(T)=D(LT)+D(RT)+k=d(i)+d(ki)+k

因此得证。

d)

f(i)f(i)f(i)=0=ilgi+(ki)lg(ki)=lgi+1lg(ki)1=lgikilgiki=0i/(ki)=1i=k2

因而在 i=k2 得到最小值。用归纳法证明 d(k)=Ω(klgk)
d(1)0=c1lg1 对任意 c 成立 。设对 i 时成立。
d(k)=min1xk1{d(i)+d(ki)+k}min1xk1{c(ilgi+(ki)lg(ki))+k}=min1xk1{cfk(i)+k}=c(k2lgk2(kk2)lg(kk2))+k=cklgk2+k=cklgk+(kck)cklgkc1

得证。

e) TA n! 个叶结点,所以 D(n)>d(k)=Ω(n!lg(n!)) 。每种排序的概率为 1/n! ,因此期望运行时间:

Ω(n!lg(n!))n!=Ω(lg(n!))=Ω(nlgn)

f) 为了构建和 B 相对应确定算法 A,我们只需选一个孩子结点来替换那个随机的结点。新的子树以及这颗子树可选择的数将小于等于随机算法对应的子树,对任意子树有 Ω(nlgn) 选择方式。也就意味着 B Ω(nlgn)

思考题8-2

a) 计数排序。

b) 快排中的PARTITION即可实现。

c) 冒泡排序、插入排序都可。

d) 基数排序需要使用稳定的排序方法,因此必须满足条件2。所以只有计数排序可以。

e) 给一个简单的方法。我们先统计每个记录出现的次数,然后直接放入数组中,举例 1,3,2,3,1,1,2, COUNT 数组中分别是 COUNT[1]=3COUNT[2]=2COUNT[3]=2 。然后数组 A[02]=1A[34]=2A[56]=3
显然这个是不稳定的。

#include <iostream>
#include <cstring>
using std::cout;
using std::endl;

void COUNT_SORT(int *array,int length,int max_int_k)
{
    int *C = new int[max_int_k+1];
    memset(C,0,sizeof(int)*(max_int_k+1));
    for(int i = 0; i < length; ++i)
        ++C[array[i]];
    int cnt = 0;
    for(int i = 1; i <= max_int_k; ++i)
    {
        while(C[i] > 0)
        {
            array[cnt++] = i;
            --C[i];
        }
    }
    delete []C;
}

int main()
{
    int ia[] = {1,3,2,3,1,1,2,7};
    COUNT_SORT(ia,8,7);
    for(int i = 0; i < 8; ++i)
        cout << ia[i] << ' ';
    cout << endl;
    return 0;
}

思考题8-3

a) 首先假设全部是整数并且数字没有前导 0 ,即没有 001 这种数字。先将相同数字位数的分成一组并用计数排序对每组数字排序,然后用基数排序对每个组排序。
设数字位数为 i 的有 mi 个,所以 i=1nimi=n 。计数排序 O(n) ,基数排序 O(n) ,总的为 O(n)

b) 将首字母相同的分成一组,使用计数排序第一个字母;若第一个字母相同,则去掉首字母再分组,递归排序直到只有一个字母。需要注意的是长度为 l 的字符串可能需要 l+1 次计数排序(如 ab a ,要排序必须把 b 和空字符比较)。运行时间是 O(n)

思考题8-4

a) 很简单,比较每个红色和蓝色水壶,即暴力破解,总时间 Θ(n2)

b) 类似决策树模型,结点内部是要比较的两个水壶,比较结果引出三条边,红色大于蓝色、等于蓝色、小于蓝色。叶结点就是匹配的水壶。 n 个红色和蓝色水壶一共有 n! 种组合方式,若树高为 h l 个叶结点,类似 8.1 节有: n!l3hhΩ(nlgn)

c)
1.随机选一个红色水壶 O(1)
2.找出对应的蓝色水壶 O(n)
3.挑出的红色水壶在和蓝色组水壶对比时,蓝色水壶就可以分成两组(可能一组为空);
4.类似 3,步骤 2 选出的蓝色水壶对比红色组,红色水壶分成两组;
5.分别递归划分的两组水壶。显然期望比较次数 O(nlgn) ,最坏情况下是 O(n2)

下面的代码用两组数字代表两种颜色不同大小的水壶,最后排序两组数表示配对成功。

#include <iostream>
#include <cstdlib>
using std::cout;
using std::endl;

int partition(int *red,int *blue,int p,int r)
{
    int index_red = rand() % (r - p + 1) + p;
    int index_blue;
    //找出红色对于的蓝色的下标
    for(index_blue = p; index_blue <= r; ++index_blue)
    {
        if(red[index_red] == blue[index_blue])
            break;
    }
    //交换blue的piovt
    int temp = blue[index_blue];
    blue[index_blue] =  blue[r];
    blue[r] = temp;
    //划分blue
    int i = p - 1;
    int blue_pivot = red[index_red];//蓝色不能和蓝色的水壶比较,所以此处用的红色
    for(int j = p; j < r; ++j)
    {
        if(blue[j] <= blue_pivot)
        {
            ++i;
            temp = blue[j];
            blue[j] = blue[i];
            blue[i] = temp;
        }
    }
    temp = blue[r];
    blue[r] = blue[i+1];
    blue[i+1] = temp;

    //交换red的piovt
    temp = red[index_red];
    red[index_red] = red[r];
    red[r] = temp;
    //划分red
    int k = p - 1;
    int red_piovt = blue[i+1];
    for(int j = p; j < r; ++j)
    {
        if(red[j] <= red_piovt)
        {
            ++k;
            temp = red[j];
            red[j] = red[k];
            red[k] = temp;
        }
    }
    temp = red[r];
    red[r] = red[k+1];
    red[k+1] = temp;

    //返回划分的下标
    return k + 1;
}

void match_jugs(int *red,int *blue,int p,int r)
{
    if(p < r)
    {
        int q = partition(red,blue,p,r);
        match_jugs(red,blue,p,q-1);
        match_jugs(red,blue,q+1,r);
    }
}

int main()
{
    int ia[] = {13,-3,-25,20,-16,-23,18};
    int ib[] = {18,20,-3,-23,13,-16,-25};
    match_jugs(ia,ib,0,6);
    for(int i = 0; i < 7; ++i)
        cout << ia[i] << ' ';
    cout << endl;
    for(int i = 0; i < 7; ++i)
        cout << ib[i] << ' ';
    cout << endl;
    return 0;
}

思考题8-5

a) 就是普通的排序。

b) 2,1,4,3,6,5,8,7,10,9 .

c)证明:

j=ii+k1A[j]kj=i+1i+kA[j]kA[i]+j=i+1i+k1A[j]kj=i+1i+k1A[j]+A[i+k]kA[i]kA[i+k]kA[i]A[i+k]

d) 由 c) 的证明,可以将数组分成 k 组,即 i,i+k,i+2k一组,每组 n/k 个,每组快速排序时间 O(nklgnk) ,总时间是 kO(nklgnk)=O(nlgnk)

e) 和练习 6.5-9 十分类似,建一个堆,运行时间是 O(nlgk) (参考6.5-9)。

f) 一共 k 组,每组 n/k 个,每组至少 Ω(nklgnk) ,总的就是 Ω(nlgnk) 。当 k 是常数时有 Ω(nlgn)

思考题8-6

a) 2n 个数中选 n 个,即 (2nn)

b) 首先 (2nn)=22nπn(1+O(1/n)) ,根据决策树模型,设有 l 个叶子结点,树高 h 得:

22nπn(1+O(1/n))l2h

化简有:
hlg(22nπn(1+O(1/n)))=lg22nlgπn+lg(1+O(1/n))=2no(n)

c) 很明显,不比较怎么知道哪个元素出列。

d) 对元素 a1,b2,a2,b2,,an,bn 分成子表 a1,a2,,an b1,b2,,bn ,一共有 2n1 对元素需要比较,所以需要比较 2n1 次。

思考题8-7

题目出奇的长,实在不想看,附一个链接,答案见此处这里写链接内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值