算法设计与分析基础(六)

算法设计与分析基础(六)

练习题

练习一

  1. 对 f(n)=n, 并且 a = b 的情况,证明递归方程T(n)=aT(n/b)+f(n)的解为O(nlogn).

    证明:

  • image-20211212213353990

练习二

  1. 设计求解n个数字之和的分治算法,给出伪代码描述并分析算法的计算复杂度(每次分为2个子问题)。

    算法思想:将n个待相加的元素分割成2个大致相等的子集合AB;对每一个子集合分别递归求和;再将每个子集的和相加。当n等于1时递归终止,此时所求之和为该元素自身。

    伪代码:

    Algorithm Sum (A[0 ... n-1])
    //输入:n个数字
    //输出:n个数字的和
     if n>1 then
    sum := Sum(A[0... └ n/2-1]) + Sum(A[ └n/2...n-1])return sum
    else return A[0]             
    

    时间复杂度分析:设T(n) 为算法计算n个数字之和所花费的基本运算次数。此时的基本运算为加法。显然,当n=1时,T(n)=0; n>1时,不失一般性,假设n=2k,其中k为某个正整数,则

    image-20211212214616450
    算法也可以按照如下形式描述:

    Algorithm Sum (arr, i, j)		
    //arr为待求和的数组,i指向第一个元素,j指向最后一个元素
    Begin
    	m :=(i+j)/2if i=j then return arr[i] 
    	     else return Sum(arr, i, m) + Sum(arr, m+1, j)
    end
    

练习三

  1. 假设R与S 分别为具有r个与s个元素的有序表,其中s ≤ log r . 设计一个最坏情况下O(log2r)时间的算法, 将R与S合并成一个有序表.

    image-20211213001254620

    算法思想:

    b1, b2, …, bs 依次插入到有序表R中。对于元素bj , 在R上使用二分查找方法,找到bj所要插入的位置。假设bj插入后的状态为

    a1, a2, …, ak, bj, ak+1, ak+2, …, ar

    由于bj≤bj+1,则将bj+1插入R时的工作可在有序子序列ak+1, ak+2, …, ar上进行,从而对S中的每个元素在R上实施二分查找插入方法的序列长度始终不超过r。根据二分查找算法的复杂度为O(logr),得知归并RS的算法复杂度为O(s·logr)。由于s≤logr,得出算法复杂度为 O(log2r)

    算法形式化描述:

        Algorithm Merger (R, S)
        Begin
        1.	Temp := R;
        2.	for i := 1 to s do
        2.1.	k := Binsearch(bi , Temp);
        2.2.	将bi 插入到R中,并更新R ;
        2.3.	Temp := (ak+1, ak+2, ..., ar );
            end of for;
        3.	return(R);
        end
    

    image-20211213005431784

练习四

  1. 给定长度为n的表,表中的所有元素已构成k个有序段, 设计一个计算复杂度为O(n log k)的算法完成对表元素的排序。给出算法的形式化描述与复杂度分析。

    解法一:

    解:假定k个有序段依次为L1,L2,…,Lk,其中每个Li的长度为 li,1 ≤ i ≤ k,则l1+l2+…+lk = n

    image-20211213005815686

    image-20211213005945138

    算法形式化描述:

        Algorithm Sort(A)
        begin
        If k = 1 then return(A)
        else begin
        1.  m := ┍k/2;
        2.  B := {L1,L2,...,Lm};
        3.  C := {Lm+1,Lm+2...,Lk};
        4.  Sort(B);
        5.  Sort(C);
        6.  Merge(B,C,A);
        end;
        end.
    

    image-20211213010358347

    解法二:

    k个有序段的首位元素建立堆(建立最小堆),在此堆上连续地进行删除操作以达到归并的目的。当堆顶元素被删除后,其所在的有序段增补一个次小元素入堆并完成堆化。

    算法描述性分析:

    //Input: k个链表,记为A[k]
    //Output: 有序序列B[n]
    Begin
    	For i:=1 to k do
    		B[i]:= A[i].value
    Createheap(B,index) //index记录最小堆中元素对应于A的索引
    While i != n do 
    Begin
    	If(A[index[0]].next != 0) then
    		B[0] := A[index[0]].next.value
    	Else:
    		B[0] := B[k]
    		Swap(index[0],index[k])
    k:=k-1
    	k:=k-1
    		AdjustHeap(B,0,k)
    	end
    end
    

    时间复杂度分析:

    假设k个有序段均为非降序排列的。

    (1)取k个元素建立最小堆,这k个元素分别是k个有序段的第一个元素。建立最小堆的时间复杂度为O(k)。

    (2)此时,该最小堆的堆顶元素就是k个有序段中最小的那个元素,将它取出返回,时间复杂度O(1)。

    (3)若堆顶元素所在有序段链表不为空,则取下一个元素放到堆顶位置,进行堆调整,堆调整时间复杂度 O(logk)。若为空,此子链表已经被合并完毕,则删除最小堆的堆顶元素,此时最小堆的结点数减小了1 ,删除指定元素的时间复杂度O(logk)。

    (4)重复步骤(2)、(3)n-k次。总的时间复杂度是O(k)+O(nlogk)即O(nlogk)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值