算法导论2.3练习答案

2.3-1使用图2-4作为模型,说明归并排序在数组A=<3,41,52,26,38,57,9,49>上的操作。


在这里插入图片描述

2.3-2重写过程MERGE,使之不使用哨兵,而是一旦数组L或R的所有元素均被复制回A就立即停止,然后把另一个数组的剩余部分复制回A。


使用哨兵的归并排序(MERGE-SORT)见文章:C语言实现归并排序
无哨兵版:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

void merge(int A[], int p, int q, int r) {
    int n1 = q - p + 1;
    int n2 = r - q;
    int* L = (int*)calloc(n1, sizeof(int));
    int* R = (int*)calloc(n2, sizeof(int));
    int i, j;
    //A[p..q]复制到L
    for (i = 0; i < n1; i++)
        L[i] = A[p + i];
    //A[q+1..r]复制到R
    for (j = 0; j < n2; j++)
        R[j] = A[q + j+ 1];
    i = j = 0;
    for (int k = p; k <= r; k++) {
        //L中的元素复制完毕,只需继续复制R中的
        if (i >= n1) {
            A[k] = R[j];
            j++;
        }
        //R中的元素复制完毕,只需继续复制L中的
        else if (j >= n2) {
            A[k] = L[i];
            i++;
        }
        //从L、R数组中取更小的元素插入A数组
        else if (L[i] <= R[j]) {
            A[k] = L[i];
            i++;
        }
        else {
            A[k] = R[j];
            j++;
        }
    }
    free(L);
    free(R);
}

void mergeSort(int A[], int p, int r) {
    //若不满足下面的if条件,则跳出当前递归返回上一层
    if (p < r) {
        int q = (int)floor(((double)p + r) / 2.0);
        mergeSort(A, p, q);
        mergeSort(A, q + 1, r);
        merge(A, p, q, r);
    }
}

main(){
	//测试
    int A[] = { 5,2,4,7,1,3,2,6 };
    mergeSort(A, 0, 7);
    for (int i = 0; i < 8; i++)
        printf("%d ", A[i]);
}

2.3-3使用数学归纳法证明:当n刚好是2的幂时,以下递归式的解是T(n)=nlgn

T ( n ) = { 2 , n = 2 2 T ( n / 2 ) + n , n = 2 k ( k > 1 ) T(n) = \begin{cases} 2 &\text{},n=2\\ 2T(n/2)+n &\text{},n=2^k(k>1) \end{cases} T(n)={22T(n/2)+n,n=2,n=2k(k>1)


(1). n = 21时,T(n) = 2 = 2lg2
(2). 假设 n = 2k时,T(n) = nlgn = 2klg2k = k2k
则对于 n = 2k+1,有
T(n) = 2T(2k+1 / 2) + 2k+1
= 2k⋅2k + 2k+1
= (k + 1)2k+1
= 2k+1lg2k+1
= nlgn
证毕。

2.3-4我们可以把插入排序表示为如下的一个递归过程。为了排序A[1…n],我们递归地排序A[1…n-1],然后把A[n]插入已排序的数组A[1…n-1]。为插入排序的这个递归版本的最坏情况运行时间写一个递归式。


最坏情况下将A[n]插入到子序列A[1…n-1]需要花费Θ(n)时间。
T ( n ) = { Θ ( 1 ) , n = 1 T ( n − 1 ) + Θ ( n ) , n > 1 T(n) = \begin{cases} \Theta(1) &\text{},n=1\\ T(n-1)+\Theta(n) &\text{},n>1 \end{cases} T(n)={Θ(1)T(n1)+Θ(n),n=1,n>1
时间复杂度为(n-1)Θ(n)+Θ(1)=Θ(n2)

2.3-5回顾查找问题(参见练习2.1-3),注意到如果序列A已排好序,就可以将该序列的中点与v进行比较。根据比较的结果,原序列中就有一半可以不用再做进一步的考虑了。二分查找算法会重复这个过程,每次都将序列剩余的部分规模减半。为二分查找写出迭代或递归的伪代码。证明:二分查找最坏情况运行时间为θ(lgn)。


伪代码:
1.迭代版

ITERATIVE-BINARY-SEARCH(A,v)
	low=1
	high=A.lehgth
	while low<=high
		mid=(low+high)/2
		if v==A[mid]
			return mid
		else if v<A[mid]
			high=mid-1
		else
			low=mid+1
	return NIL

2.递归版

RECURSIVE-BINART-SEARCH(A,v,low,high)
	if low>high
		return NIL
	mid=(low+high)/2
	if v==A[mid]
		return mid
	else if v<A[mid]
		return RECURSIVE-BINART-SEARCH(A,v,low,mid-1)
	else
		return RECURSIVE-BINART-SEARCH(A,v,mid+1,high)

C语言代码见文章:C语言实现二分查找,折半查找(迭代/递归)
递归式
T ( n ) = { Θ ( 1 ) , n = 1 T ( n / 2 ) + Θ ( 1 ) , n > 1 T(n) = \begin{cases} \Theta(1) &\text{},n=1\\ T(n/2)+\Theta(1) &\text{},n>1 \end{cases} T(n)={Θ(1)T(n/2)+Θ(1),n=1,n>1
可自行使用递归树进行分析,设递归树的高度为h,则2h=n,共有(lgn + 1)个 Θ(1)。
所以最坏情况下 T(n) = (lgn + 1)Θ(1) = Θ(lgn)

2.3-6注意到2.1节中的过程INSERTION-SORT的第5~7行的while循环采用一种线性查找来(反向)扫描已排好序的子数组A[1…j-1]。我们可以使用二分查找(参见练习2.3-5)来把插入排序的最坏情况总运行时间改进到θ(nlgn)吗?


不可以
算法分析与代码实现:二分查找插入排序(优化的直接插入排序)
最坏情况下需要对1 + 2 + 3 + … + (n - 1) = n(n - 1)/2个元素后移,需要的赋值操作次数为n(n - 1)/2 + (n - 1),排序的时间复杂度仍为O(n2)

2.3-7描述一个运行时间为O(nlgn)的算法,给定n个整数的集合S和另一个整数x,该算法能确定S中是否存在两个其和刚好为x的元素。


首先使用归并排序对集合S进行排序,这一步的运行时间为O(nlgn),然后对S中任一元素 si 使用二分查找在子序列 S[i+1…n] 中检索值为 x - si 的元素。这一步的运行时间为 O(lgn)。
综上,该算法的运行时间为 O(nlgn) + n⋅O(lgn) = O(nlgn)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值