CLRS第二章思考题

思考题2-1

a) 长度为 k 的表所需时间 ak2+bk+c,其中 a,b,c 是常数,对 nk 个这样的表需要 nk(ak2+bk+c) ,即 Θ(nk)

b) 如果把合并 2 个表拓展到一次合并所有的表则需要 Θ(nnk)=Θ(n2k) (每次从 nk 个表中选择一个最小元素放入到最终表中,重复 n 次)。
要达到 Θ(nlgnk),我们两两合并,即每次合并两个表,然后把两个表合并的结果和另外两个表合并的结果再次两两合并,每一层合并需要 Θ(n) ,一个有 lg(n/k) 高度,所以总时间就是 Θ(nlg(n/k))

c) 当 k=Θ(lgn) 时,有 Θ(nk+nlg(n/k))=Θ(nk+nlgnnlgk)=Θ(2nlgnnlglgn)=Θ(nlgn)

d) 只需计算出当插入排序击败归并排序时的最大 k 值即可,选择此 k 值就行。

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

const int treshold = 20;        //此阈值只做测试之用,不是实际k值

void insertion_sort(int *array,int p,int r)
{
    for(int i = p + 1; i <= r; ++i)
    {
        int key = *(array + i);
        int j = i - 1;
        while(j >= p && *(array + j) > key)
        {
            *(array + j + 1) = *(array + j);
            --j;
        }
        *(array + j + 1) = key;
    }
}

void merge(int *array,int p,int q,int r)
{
    int n1 = q - p + 1;
    int n2 = r - q;
    int *L = new int[n1];
    int *R = new int[n2];
    int i = 0, j = 0;
    for(int k = p; k <= q; ++k)
        *(L + i++) = *(array + k);
    for(int k = q + 1; k <= r; ++k)
        *(R + j++) = *(array + k);
    i = j = 0;
    for(int k = p; k <= r; ++k)
    {
        if(i == n1)
            *(array + k) = *(R + j++);
        else if(j == n2)
            *(array + k) = *(L + i++);
        else if(*(L + i) <= *(R + j))
            *(array + k) = *(L + i++);
        else *(array + k) = *(R + j++);
    }
    delete []L;
    delete []R;
}

void mixed_merge_sort(int *array,int p,int r)
{
    if(p < r)
    {
        if(r - p > treshold)
        {
            int q = (p + r) / 2;
            mixed_merge_sort(array,p,q);
            mixed_merge_sort(array,q+1,r);
            merge(array,p,q,r);
        }
        else insertion_sort(array,p,r);
    }
}

int main()
{
    int *array;
    int len,key;
    cout << "input the length of array" << endl;
    cin >> len;
    array = new int[len];
    cout << "input " << len << " integers" << endl;
    for(int i = 0; i < len; ++i)
        cin >> *(array + i);
    mixed_merge_sort(array,0,len-1);
    cout << "after sort" << endl;
    for(int i = 0; i < len; ++i)
        cout << *(array + i) << ' ';
    cout << endl;
    delete []array;
    return 0;
}

思考题2-2

a) 我们需要证明 A A 的一个排列,即 A' 的元素全是 A 中的元素。

b) 每次内部迭代开始时,A[j]=min{A[k]:jkn},并且显然 A[jn] 是初始 A[jn] 的一个排列。
初始化: j=nA[jn] 仅有一个元素 A[n] ,显然成立;
保持:根据循环不变式, A[j] A[jn] 的最小元素,若 A[j1]>A[j] ,则交换它们使得 A[j1] A[j1n] 的最小值,而且每次只是交换两个值,因此 A[j1n] 必然是 A[j1n] 的一个排列;
终止:当 j=i 时循环终止, A[i]=min{A[k]:ikn} ,并且 A[in] 是初始 A[in] 的一个排列。

c) 每次迭代开始时, A[1i1] 包含初始 A[1n] 最小的 i1 个元素,且 A[1]A[2]A[i1]
初始化:当 i=1 时, A[1i1] 为空,循环成立;
保持: A[1i1] 包含初始 A[1n] 最小的 i1 个元素,且 A[1]A[2]A[i1] 。内部循环使得 A[i] A[in] 的最小元素,所以现在 A[1i] 是初始 A[1i] 元素的非递减排列;
终止:当 i=n 时循环终止, A[1i1 ] 即 A[1n1] 是初始 A[1n1] 的非递减排列,包含 A 中最小 n1 个元素,显然 A[n] A 中最大的元素,所以 A[1n] 是排序后的序列。

d) 最坏运行时间是 Θ(n2) ,与插入排序运行时间一样。
附上冒泡排序代码:

void bubble_sort(int *array,int length)
{
    for(int i = 0; i < length - 1; ++i)
    {
        for(int j = length - 1; j > i; --j)
        {
            if(*(array + j) < *(array + j - 1))
            {
                int temp = *(array + j);
                *(array + j) = *(array + j - 1);
                *(array + j - 1) = temp;
            }
        }
    }
}

思考题2-3

a) Θ(n)
b) 伪代码如下,运行时间为 Θ(n2) ,显然变慢了。

y = 0
for i = 0 to n
    t = 1
    for j = 1 to i
        t = t·x
    y = y + t·a

c) 初始化:累加项为空,成立;
保持:在第 i 次迭代结束时有:

y=ai+xk=0n(i+1)ak+i+1xk=aix0+k=0ni1ak+i+1xk+1==aix0+k=1niak+ixk=k=0niak+ixk

终止:当 i=1 时循环终止,带入循环不变式得

y=k=0ni1ak+i+1xk=k=0nakxk

d) 由c)显然正确得出 a0,a1,an ,循环不变式的总和等于给定的系数多项式和。

思考题2-4

a) <8,6><2,1><3,1><8,1><6,1> <script type="math/tex" id="MathJax-Element-101"><8,6>、<2,1>、<3,1>、<8,1>、<6,1></script>
b) 当集合是逆序排列时逆序对最多,一共有 n1+n2++1=n(n1)2 对。

c) 每有一个逆序对就意味着插入排序需要改变这两个元素的位置。也就是每交换一对元素,就会消除一对原序列中的逆序对,所以逆序对和插入排序运行时间是同数量级的。

d) 我们知道归并排序运行时间是 Θ(nlgn) ,在归并排序中合并两个子表的时候需要比较两个子表当前元素的大小(不妨称呼为 L 表和 R 表,另外有两个指针分别指向 L R 表中需要比较的元素),然后将较小的元素放入到最终数组中,并使指向较小元素的指针后移。假设当前指向 L 表中的元素比指向 R 表中的元素要大,这说明指向 L 表的元素以及 L 表中该元素的后面所有元素都大于指向 R 表的元素,因此可得到 L 表中这一段的逆序对。一直求 L 表中的逆序即可得到总对数。反之也可以求 R 表中的逆序对数。通过改变归并排序即可在 Θ(nlgn) 求出逆序对数。

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

int merge(int *array,int p,int q,int r)
{
    int n1 = q - p + 1;
    int n2 = r - q;
    int *L = new int[n1];
    int *R = new int[n2];
    int i = 0, j = 0;
    for(int k = p; k <= q; ++k)
        *(L + i++) = *(array + k);
    for(int k = q + 1; k <= r; ++k)
        *(R + j++) = *(array + k);
    i = j = 0;
    int  inversions = 0;
    for(int k = p; k <= r; ++k)
    {
        if(i == n1)
            *(array + k) = *(R + j++);
        else if(j == n2)
            *(array + k) = *(L + i++);
        else if(*(L + i) <= *(R + j))
            *(array + k) = *(L + i++);
        else
        {
            *(array + k) = *(R + j++);
            inversions += n1 - i;
        }
    }
    delete []L;
    delete []R;
    return inversions;
}

int inversions_merge_sort(int *array,int p,int r)
{
    int  inversions = 0;
    if(p < r)
    {
        int q = (p + r) / 2;
        inversions += inversions_merge_sort(array,p,q);
        inversions += inversions_merge_sort(array,q+1,r);
        inversions += merge(array,p,q,r);
    }
    return inversions;
}

int main()
{
    int *array;
    int len,key;
    cout << "input the length of array" << endl;
    cin >> len;
    array = new int[len];
    cout << "input " << len << " integers" << endl;
    for(int i = 0; i < len; ++i)
        cin >> *(array + i);
    cout << "Total inversions: " << inversions_merge_sort(array,0,len-1) << endl;
    delete []array;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值