O(N)+x=2*O(N/2)+2*x
a*O(N)+x=a*(2*O(N/2)+x)+x=2*a *O(N/2)+(a+1)*x 由此可知,时间复杂度可达到O(n);
3.分治策略一定导致递归吗如果是,请解释原因。如果不是,给出一个不包含递归的分治例子,并阐述这种分治和包含递归的分治的主要不同。
不一定导致递归。
如非递归的二叉树中序遍历。
这种分治方法与递归的二叉树中序遍历主要区别是:应用了栈这个数据结构。
4. 对于待排序序列(5, 3, 1, 9),分别画出归并排序和快速排序的递归运行轨迹。
归并排序:
第一趟:(5,3)(1,9); 第二趟:(3,5,1,9); 第三趟:(1,3,5,9);
快速排序:
第一趟:5( ,3,1,9);设计分治算法求一个数组中的最大元素,并分析时间性能。
设计分治算法,实现将数组A[n]中所有元素循环左移k个位置, 要求时间复杂性为O(n),空间复杂性为O(1)。例如,对abcdefgh循环左移3位得到defghabc。
设计递归算法生成n个元素的所有排列对象。
#include
int data[100];
设计分治算法求解一维空间上n个点的最近对问题。
参见最近对问题的算法分析及算法实现
9. 在有序序列(r1, r2, …, rn)中,存在序号i(1≤i≤n),使得ri=i。请设计一个分治算法找到这个元素,要求算法在最坏情况下的时间性能为O(log2n)。
在一个序列中出现次数最多的元素称为众数。请设计算法寻找众数并分析算法的时间复杂性。
设M是一个n×n的整数矩阵,其中每一行(从左到右)和每一列(从上到下)的元素都按升序排列。设计分治算法确定一个给定的整数x是否在M中,并分析算法的时间复杂性。
12. 设S是n(n为偶数)个不等的正整数的集合,要求将集合S划分为子集S1和S2,使得| S1|=| S2|=n/2,且两个子集元素之和的差达到最大。
设a1, a2,…, an是集合{1, 2, …, n}的一个排列,如果i
k循环赛日程安排问题。设有n=2个选手要进行网球循环赛,要求设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次; (2)每个选手一天只能赛一次。
采用分治方法。
将2^k选手分为2^k-1两组,采用递归方法,继续进行分组,直到只剩下2个选手时,然后进行比赛,回溯就可以指定比赛日程表了
n15. 格雷码是一个长度为2的序列,序列中无相同元素,且每个元素都是长度为n的
3
二进制位串,相邻元素恰好只有1位不同。例如长度为2的格雷码为(000, 001, 011, 010, 110, 111, 101, 100)。设计分治算法对任意的n值构造相应的格雷码。
矩阵乘法。两个n×n的矩阵X和Y的乘积得到另外一个n×n的矩阵Z,且Zij
满足 (1≤i, j≤n),这个公式给出了运行时间为O(n)的算法。可以用分 治法解决矩阵乘法问题,将矩阵X和Y都划分成四个n/2×n/2的子块,从而X和Y的乘积可以用这些子块进行表达,即
3
从而得到分治算法:先递归地计算8个规模为n/2的矩阵乘积AE、BG、AF、BH、CE、DG、CF、DH,然后再花费O(n2)的时间完成加法运算即可。请设计分治算法实现矩阵乘法,并分析时间性能。能否再改进这个分治算法
习题5
1. 下面这个折半查找算法正确吗如果正确,请给出算法的正确性证明,如果不正确,请说
明产生错误的原因。
int BinSearch(int r[ ], int n, int k) {
int low = 0, high = n - 1; int mid;
while (low <= high) {
mid = (low + high) / 2; if (k < r[mid]) high = mid;
else if (k > r[mid]) low = mid;
else return mid; }
return 0; }
错误。 正确算法:
int BinSearch1(int r[ ], int n, int k) {
int low = 0, high = n - 1; int mid;
while (low <= high) {
mid = (low + high) / 2; if (k < r[mid]) high = mid - 1;
else if (k > r[mid]) low = mid + 1;
else return mid; }
return 0; }
2. 请写出折半查找的递归算法,并分析时间性能。
求两个正整数m和n的最小公倍数。(提示:m和n的最小公倍数lcm(m, n)与m和n的最大公约数gcd(m, n)之间有如下关系:lcm(m, n)=m×n/gcd(m, n))
插入法调整堆。已知(k1, k2, …, kn)是堆,设计算法将(k1, k2, …, kn, kn+1)调整为堆(假设调整为大根堆)。
参照:
void SiftHeap(int r[ ], int k, int n) {
int i, j, temp;
i = k; j = 2 * i + 1; 设计算法实现在大根堆中删除一个元素,要求算法的时间复杂性为O(log2n)。
计算两个正整数n和m的乘积有一个很有名的算法称
n m 为俄式乘法,其思想是利用了一个规模是n的解和一个规50 65 25 130 130 模是n/2的解之间的关系:n×m=n/2×2m(当n是偶数)
12 260 或:n×m=(n-1)/2×2m+m(当n是奇数),并以1×m=m6 520 作为算法结束的条件。例如,图给出了利用俄式乘法计算3 1040 1040 1 2080 2080 + 50×65的例子。据说十九世纪的俄国农夫使用该算法并因
3250 此得名,这个算法也使得乘法的硬件实现速度非常快,因
图 俄式乘法 为只使用移位就可以完成二进制数的折半和加倍。请设计算法实现俄式乘法。
拿子游戏。考虑下面这个游戏:桌子上有一堆火柴,游戏开始时共有n根火柴,两个玩家轮流拿走1,2,3或4根火柴,拿走最后一根火柴的玩家为获胜方。请为先走的玩家设计一个制胜的策略(如果该策略存在)。
如果桌上有小于4根的火柴,先手必胜,如果是5根,先手必输;依次类推,同理15、20、25…….都是必输状态;所有每次把对手逼到15、20、25…….等必输状态,就可以获胜。
9. 竞赛树是一棵完全二叉树,它反映了一系列“淘汰赛”的结果:叶子代表参加比赛的n个选手,每个内部结点代表由该结点的孩子结点所代表的选手中的胜者,显然,树的根结点就代表了淘汰赛的冠军。请回答下列问题:
(1)这一系列的淘汰赛中比赛的总场数是多少
(2)设计一个高效的算法,它能够利用比赛中产生的信息确定亚军。
(1)因为n人进行淘汰赛,要淘汰n-1人,所有要进行n-1场比赛。 (2)
10. 在120枚外观相同的硬币中,有一枚是假币,并且已知假币与真币的重量不同,但不知道假币与真币相比较轻还是较重。可以通过一架天平来任意比较两组硬币,最坏情况下,能不能只比较5次就检测出这枚假币
将120枚平均分为三组,记为:A,B,C;先将A,B比较,如果A,B重量不同(假如B比A重),再将B与C比较,如果B,C相同,则A有假币;如果B,C不同,再将A,C比较,如果A,C相同,则B有假币;如果A,C不同,则B有假币;如果A,B相同,则C有假币;
相关推荐: