第四章 递归和分治
算法设计与分析(王晓东)

a b a b
(2)方法重载:Java允许方法重载,即允许定义有不同签名的同名方法。
上述方法ab可重载为:
public static double ab(double a, double b) { return (a+b+Math.abs(a-b))/2.0; } 12
4.异常
1.3 描述算法
6
1.2 表达算法的抽象机制
2.抽象数据类型
抽象数据类型是算法的一个数据模型连同定义在该模型上 并作为算法构件的一组运算。
抽象数据类型带给算法设计的好处有:
(1)算法顶层设计与底层实现分离; (2)算法设计与数据结构设计隔开,允许数据结构自由选择; (3)数据模型和该模型上的运算统一在ADT中,便于空间和时间耗费的折衷; (4)用抽象数据类型表述的算法具有很好的可维护性; (5)算法自然呈现模块化; (6)为自顶向下逐步求精和模块化提供有效途径和工具; (7)算法结构清晰,层次分明,便于算法正确性的证明和复杂性的分析。
中国计算机学会 “21世纪大学本科计算机专业系列教材”
算法设计与分析
王晓东 编著
1
主要内容介绍
• • • • • • 第1章 第2章 第3章 第4章 第5章 第6章 算法引论 递归与分治策略 动态规划 贪心算法 回溯法 分支限界法
启发式规则_分治法汉诺塔4

汉诺塔问题可以通过以下三个步骤实现: (1)将塔A上的n-1个碟子借助塔C先移到塔B上。 (2)把塔A上剩下的一个碟子移到塔C上。 (3)将n-1个碟子从塔B借助塔A移到塔C上。 显然,这是一个递归求解的过程
Hanoi塔问题, 算法分析如下,设A上有n个盘子。 如果n=1,则将圆盘从A直接移动到C。 如果n=2,则: (1)将A上的n-1(等于1)个圆盘移到B上; (2)再将A上的一个圆盘移到C上; (3)最后将B上的n-1(等于1)个圆盘移到C上。 如果n=3,则: A)将A上的n-1(等于2,令其为n`)个圆盘移到B(借助于C),步 骤如下: (1)将A上的n`-1(等于1)个圆盘移到C上。 (2)将A上的一个圆盘移到B。 (3)将C上的n`-1(等于1)个圆盘移到B。 B)将A上的一个圆盘移到C。 C)将B上的n-1(等于2,令其为n`)个圆盘移到C(借助A),步骤 如下: (1)将B上的n`-1(等于1)个圆盘移到A。 (2)将B上的一个盘子移到C。 (3)将A上的n`-1(等于1)个圆盘移到C。到此,完成了三个圆盘的 移动过程。
5, 3, A, B, C ⑴
5, 2, A, C, B 5, 3, A, B, C
⑹ 7, 1, A, B, C 7, 2, B, A, C 5, 3, A, B, C ⑾
5, 3, A, B, C ⑺
7, 2, B, A, C 5, 3, A, B, C
⑻
7, 2, B, A, C 5, 3, A, B, C ⑽
4.2 递 归
4.2.1 递归的定义
4.2.2 递归函数的运行轨迹
4.2.3 递归函数的内部执行过程
4.2.1 递归的定义
递归(Recursion)就是子程序(或函数)直 接调用自己或通过一系列调用语句间接调用自己, 是一种描述问题和解决问题的基本方法。 递归有两个基本要素: ⑴ 边界条件:确定递归到何时终止; ⑵ 递归模式:大问题是如何分解为小问题的。
苏州大学计算机硕士算法期末整理

第三章-递归1.统计二叉树高度递归转非递归2.层次遍历递归转非递归,时空复杂度3.求树的叶节点数递归转非递归4.最后三位010(习题3.6)5.第一次010(习题3.7)6.Fabonacci递归转非递归7.欧几里得算法8.递归实现二分检索9.Fabonacci非递归(2)10.补充:证明Tn=T(n/9)+ T(63n/72)+C1n11.MAXMIN递归转非递归第四章-分治1. 稳定快排2. 完全三叉树的成功检索效率(P76有二叉树的)3. 求解递归关系式(习题4.2)4. 二分检索(递归)(习题4.3)5. MAXMIN递归转非递归(习题4.8)(第三章11)6. 稳定快排(习题4.13)7. 补充:证明E=I+2n第五章-贪心1.期限作业2.01背包(习题5.3)3.集合覆盖(习题5.4)4.结点覆盖(习题5.5)5.期限作业(习题5.8)6.最优三元归并树(习题5.12)7.在假定图用邻接表来表示的情况下重写Prim,计算复杂度(习题5.14)8.补充:用集合算法,求图是否有回路9.补充:用集合算法,求图是否为连通图第六章-动规1.最优二分检索树2.三级系统,成本与可靠性3.货郎担问题4.流水线调度问题P150例题6.19 第七章-基本检索与周游设计算法,输出遍历的二叉树第八章-回溯N的R排列分派问题,成本最小子集合数的状态空间树NQ的状态空间树第九章-分枝限界LCKNAP(LC的背包问题)第十章-NP集团最优化问题可约化为集团的判定问题集团判定为NP难问题P问题、NP问题、NP完全问题、CNF 可满足性问题之间的关系【3.1】(1)试给出统计二叉树高度的递归算法;(2)对该递归算法用消除递归法改写递归:procedure TreeDeep (T)if T = null then deep <- 0else ldeep <- TreeDeep(T, lchild)rdeep <- TreeDeep(T, rchild)deep <- Max(ldeep, rdeep)+1endifreturn (deep)end TreeDeep非递归:Procedure TreeDeep(T)STACK(1:8n); top <- 0L1: if T = null then deep <- 0 // r2 else top <- top+1; STACK(top) <- T // r3top <- top+1; STACK(top) <- ldeep // r3top <- top+1; STACK(top) <- rdeep // r3top <- top+1; STACK(top) <- 2 // r4T <- T.lchild // r5goto L1L2: ldeep <- STACK(top); top <- top-1 // r7 top <- top+1; STACK(top) <- T // r3top <- top+1; STACK(top) <- ldeep // r3top <- top+1; STACK(top) <- rdeep // r3top <- top+1; STACK(top) <- 3 // r4T <- T.rchild // r5goto L1 // r6L3: rdeep <- STACK(top); top <- top-1 // r7 deep <- Max(ldeep, rdeep)+1endifif top = 0 then return (deep) // r8else addr <- STACK(top); top <- top-1 // r10rdeep <- STACK(top); top <- top-1 // r11ldeep <- STACK(top); top <- top-1 // r11T <- STACK(top); top <- top-1 // r11top <- top+1; STACK(top) <- deep // r12if addr = 2; then goto L2 endif // r13if addr = 3; then goto L3 endif // r13 endifend TreeDeep【3.2】三、试写出栈层次遍历一颗二叉树的算法,并给出时空复杂度procedure LEVELORDER(T)if T ≠ null thenInit(Q) //初始化队列Q为空call ADDQ(T,Q)loopif EMPTY(Q) then return endifcall DELETEQ(u,Q)print (u)if u.lchild ≠ null thencall ADDQ(u.lchild, Q)endifif u.rchild ≠ null thencall ADDR(u.rchild, Q)endifrepeatendifend LEVELORDER时间复杂度Θ(n) 空间复杂度Θ(n)【3.3】设有如下递归程序,改为非递归,求叶节点个数procedure leaf(T)if T = null then res = 0else if T是叶子then res = 1else lL = leaf(T.lchild)lR = leaf(T.rchild)res = lL+lRendifendifreturn(res)end leaf非递归:procedure leaf(T)global integer S(1:n), lL, lR, res, addrInit(S)L1: if T=n:1 then res = 0elseif T是叶子then res =1elsepush(T);push(lR);push(lL);push(2)T <- T.lchildgoto L1L2: lL <- pop(S)push(T);push(lR);push(lL);push(3)T <- T.rchildgoto L1L3: lR <- pop(S)res = lL+lRendifendifif empty(S) then return reselseaddr <- pop(S)lL <- pop(S)lR <- pop(S)T <- pop(S)push(res)if addr = 2 then goto L2 endifif addr = 3 then goto L3 endif endifend leaf【3.11】将递归过程MAXMIN翻译成在计算机上等价的非递归过程解:procedure MAXMIN(i,j,fmax,fmin)integer i,j,k; integer stack(1:4n)global n, A(1:n)top <- 0L1: case:i=j: fmax <- fmin <- A(i):i=j-1:if A(i) < A(j) thenfmax <- A(j)fmin <- A(i)elsefmax <- A(i)fmin <- A(j)endif:else:mid <- ⌊(i+j)/2⌋top <- top+1; stack(top) <- i; k <- j; j <- mid;top <- top+1; stack(top) <- j; j <- k; k <- ii <- mid+1; top <- top+1; stack(top) <- itop <- top+1; stack(top) <- j; i <- ktop <- top+1; stack(top) <- 2goto L1L2: gmax <- stack(top); top <- top-1gmin <- stack(top); top <- top-1hmax <- stack(top); top <- top-1hmin <- stack(top); top <- top-1endcaseif top = 0 thenfmax <- max(gmax, hmax)fmin <- min(gmin, hmin)elseaddr <- stack(top); top <- top-1j <- stack(top); top <- top-1; i <- stack(top); top <- top-1;j <- stack(top); top <- top-1; i <- stack(top); top <- top-1;top <- top+1; stack(top) <- hmintop <- top+1; stack(top) <- hmaxtop <- top+1; stack(top) <- gmintop <- top+1; stack(top) <- gmaxif addr=2 then goto L2 endifendifend MAXMIN【4.1】quicksort算法是一种不稳定的算法,但如果把A(i)中的值做适当变换,可使A(i)值各不相同,在分类之后,在将A(i)恢复成原来的值A(i),试给出变换和恢复表达式,并证明该式能满足要求。
递归和分治法

递归和分治法摘要:1.递归和分治法的定义2.递归和分治法的区别3.递归和分治法的应用实例4.递归和分治法的优缺点正文:递归和分治法是计算机科学中常用的两种算法设计技巧。
它们在解决问题时都采用了将问题分解成更小子问题的思路,但在具体实现上却有所不同。
下面,我们来详细了解一下递归和分治法。
1.递归和分治法的定义递归法是指在算法中调用自身来解决问题的方法。
递归函数在执行过程中,会将原问题分解成规模更小的相似子问题,然后通过调用自身的方式,解决这些子问题,最后将子问题的解合并,得到原问题的解。
分治法是指将一个大问题分解成若干个规模较小的相似子问题,然后分别解决这些子问题,最后将子问题的解合并,得到原问题的解。
分治法在解决问题时,通常需要设计一个主函数(master function)和一个子函数(subfunction)。
主函数负责将问题分解,子函数负责解决子问题。
2.递归和分治法的区别递归法和分治法在解决问题时都采用了将问题分解成更小子问题的思路,但它们在实现上存在以下区别:(1)函数调用方式不同:递归法是通过调用自身来解决问题,而分治法是通过调用不同的子函数来解决问题。
(2)递归法必须有递归出口,即必须有一个基线条件,而分治法不一定需要。
3.递归和分治法的应用实例递归法应用广泛,例如斐波那契数列、汉诺塔问题、八皇后问题等。
分治法也有很多实际应用,例如快速排序、归并排序、大整数乘法等。
4.递归和分治法的优缺点递归法的优点是代码简单易懂,但缺点是容易产生大量的重复计算,导致时间复杂度较高。
分治法的优点是时间复杂度较低,但缺点是代码实现相对复杂,需要设计主函数和子函数。
总之,递归和分治法都是解决问题的有效方法,具体应用需要根据问题的特点来选择。
分治算法知识点总结

分治算法知识点总结一、基本概念分治算法是一种递归的算法,其基本思想就是将原问题分解成多个相互独立的子问题,然后分别解决这些子问题,最后将子问题的解合并得到原问题的解。
分治算法的核心思想可以用一句话概括:分而治之,分即是将原问题分解成若干个规模较小的子问题,治即是解决这些子问题,然后将子问题的解合并起来得到原问题的解。
分治算法通常包括三个步骤:(1)分解:将原问题分解成若干个规模较小的子问题;(2)解决:递归地解决这些子问题;(3)合并:将子问题的解合并起来得到原问题的解。
分治算法的典型特征包括递归和合并。
递归指的是将原问题分解成若干个规模较小的子问题,然后递归地解决这些子问题;合并指的是将子问题的解合并得到原问题的解。
通常来说,分治算法的递归实现方式很容易编写,但有时可能会面临大量的重复计算,因此需要合并操作来避免这种情况。
二、原理分治算法的原理可以通过一个简单的例子来说明。
我们以计算数组中的最大值为例,具体的步骤如下:(1)分解:将数组分解成两个规模相等的子数组;(2)解决:递归地在这两个子数组中分别找到最大值;(3)合并:比较这两个子数组的最大值,得到原数组的最大值。
从这个例子可以看出,分治算法将原问题分解成两个子问题:分别在左边子数组和右边子数组中找到最大值,然后将这两个子问题的解合并起来得到原数组的最大值。
这种将问题分解成若干个规模较小的子问题,然后合并子问题的解得到原问题的解的方法正是分治算法的核心原理。
分治算法的优势在于它可以将原问题分解成多个规模较小的子问题,然后并行地解决这些子问题,最后合并子问题的解得到原问题的解。
这种并行的设计思路使得分治算法非常适合于并行计算,能够有效地提高计算效率。
三、应用分治算法在计算机科学领域有着广泛的应用,包括排序、搜索、图论、动态规划等多个方面。
下面我们将以排序算法和搜索算法为例,来介绍分治算法在实际应用中的具体情况。
1. 排序算法排序算法是计算机科学领域中一个重要的问题,分治算法在排序算法中有着广泛的应用。
算法设计与分析:递归与分治法-实验报告(总8页)

算法设计与分析:递归与分治法-实验报告(总8页)实验目的:掌握递归与分治法的基本思想和应用,学会设计和实现递归算法和分治算法,能够分析和评价算法的时间复杂度和空间复杂度。
实验内容:1.递归算法的设计与实现3.算法的时间复杂度和空间复杂度分析实验步骤:1)递归定义:一个函数或过程,在其定义或实现中,直接或间接地调用自身的方法,被成为递归。
递归算法是一种控制结构,它包含了解决问题的基础情境,也包含了递归处理的情境。
2)递归特点:递归算法具有以下特点:①依赖于递归问题的部分解被划分为若干较小的部分。
②问题的规模可以通过递推式递减,最终递归终止。
③当问题的规模足够小时,可以直接求解。
3)递归实现步骤:①确定函数的定义②确定递归终止条件③确定递归调用的过程4)经典实例:斐波那契数列递推式:f(n) = f(n-1) + f(n-2)int fib(int n) {if (n <= 0)return 0;else}5)优化递归算法:避免重复计算例如,上述斐波那契数列的递归算法会重复计算一些中间结果,影响效率。
可以使用动态规划技术,将算法改为非递归形式。
int f1 = 0, f2 = 1;for (int i = 2; i <= n; i++) {f1 = f2;使用循环避免递归,重复计算可以大大减少,提高效率。
1)分治算法的定义:将原问题分解成若干个规模较小且类似的子问题,递归求解子问题,然后合并各子问题得到原问题的解。
2)分治算法流程:②将问题分解成若干个规模较小的子问题。
③递归地解决各子问题。
④将各子问题的解合并成原问题的解。
3)分治算法实例:归并排序归并排序是一种基于分治思想的经典排序算法。
排序流程:②分别对各子数组递归进行归并排序。
③将已经排序好的各子数组合并成最终的排序结果。
实现源代码:void mergeSort(int* arr, int left, int right) {if (left >= right)while (i <= mid && j <= right)temp[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];temp[k++] = arr[i++];1) 时间复杂度的概念:指完成算法所需的计算次数或操作次数。
算法考试要点
计算机算法复习提纲
贪心选择性质 假设 A={X1,X2,X3...............,Xn} 是 E={E1,E2,E3,........En}活动集合的最优解,E 中活动 按照结束时间非递减排序。 如果 X1=E1,A 是以贪心选择开始的。 如果 X1 !=E1,假设 B={E1,X2,X3...............,Xn} ,又因为 F1《=Fx1 并且 A 中个活动相容, 则 B 中活动也是相容的,因此 B 是一个以贪心选择开始的最优解。 最有子结构性质 E’={E2,E3,........En} A’={X2,X3...............,Xn} 假设 A’不是 E‘的最优解,B’比 A’更优, 那么 B’U{E1}=B 优于 A’U{E1}=A,即 B 是一个更优解, 与假设 A 为最优解矛盾。 贪心选择次数由数学归纳法可以证明,因此贪心算法可以求得该问题的最优解。
{ f[1][j]=g[1][j];d[1][j]=j; } for(i=2;i<=n;i++)
for(j=0;j<=m;j++)
计算机算法复习提纲
{ f[i][j]=0; for(k=0;k<=j;k++) { s=f[i-1][j-k]+g[i][k]; if(s>f[i][j]) { f[i][j]=s; }
sum++; for (int i=1; i<=n; i++)
cout << x[i] << ' '; cout << endl; }
else for (int i=1;i<=m;i++) { x[t]=i; if (Ok(t)) Backtrack(t+1); }
递归和分治法
递归和分治法摘要:一、递归与分治法的概念1.递归:函数调用自身的思想2.分治法:把一个大问题分解成若干个小问题二、递归与分治法的联系与区别1.递归通常作为分治法的实现方式2.分治法不一定要用递归实现三、递归与分治法的应用实例1.快速排序算法2.归并排序算法3.汉诺塔问题正文:递归和分治法是两种在计算机科学中经常使用的解决问题的方法。
递归是一种函数调用自身的思想,即函数在执行过程中,会调用自身来完成某些操作。
而分治法则是把一个大问题分解成若干个小问题,然后逐个解决这些小问题,最后再把它们的解合并,得到大问题的解。
这两种方法在某些情况下可以相互转化,递归通常作为分治法的实现方式,但分治法不一定要用递归实现。
递归与分治法之间的联系在于,递归通常是分治法的实现方式。
在分治法中,我们会把一个大问题分解成若干个小问题,然后通过递归的方式,逐个解决这些小问题。
最后,再把它们的解合并,得到大问题的解。
在这个过程中,递归函数的调用栈会随着问题规模的减小而减小,最终回到原点,从而完成问题的求解。
然而,分治法并不一定要用递归实现。
在一些情况下,我们可以通过迭代的方式,逐个解决小问题,然后把它们的解合并。
这种方式虽然不是通过递归函数调用自身来实现的,但它仍然符合分治法的思想,即把大问题分解成小问题,逐个解决。
递归和分治法在实际问题中有很多应用。
例如,快速排序算法和归并排序算法都是基于分治法的思想设计的。
在快速排序算法中,我们选择一个基准元素,然后把数组中小于基准的元素放在左边,大于基准的元素放在右边,再对左右两个子数组递归地执行相同的操作,直到数组有序。
而在归并排序算法中,我们同样把数组分成左右两个子数组,然后递归地对它们进行排序,最后再把排序好的子数组合并成一个有序的数组。
另一个例子是汉诺塔问题。
在这个问题中,有三个柱子和一个大小不同的圆盘。
要求把圆盘从第一个柱子移动到第三个柱子,每次只能移动一个圆盘,并且大盘不能放在小盘上。
算法与设计实验报告
实验一分治与递归(4学时)一、实验目的与要求1、熟悉C/C++语言的集成开发环境;2、通过本实验加深对递归过程的理解二、实验内容掌握递归算法的概念和基本思想,分析并掌握“整数划分”问题的递归算法。
三、实验题任意输入一个整数,输出结果能够用递归方法实现整数的划分。
四、程序代码五、实验结果首先按照提示输入数字:按回车键,得到此数划分的个数:此时您可以接着计算另一个数的划分个数:若要退出,请输入一个小于等于零的数:六、结果分析及程序功能经过和其它同学的实验数据对比,初步认定此程序基本正确,然而不足之处是只能得到划分的个数,而不能列出每个划分的详细情况。
一、实验目的与要求1、掌握棋盘覆盖问题的算法;2、初步掌握分治算法二、实验题盘覆盖问题:在一个2k×2k个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。
在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
三、程序代码四、实验结果按照提示输入特殊方格的行号和列号(起始行列号为0):按回车键,得到一个矩阵,数字相同区域为一个L型骨牌覆盖:五、结果分析及程序功能得到的16*16棋盘覆盖结果正确,此程序的不足之处:只能设定特殊方格的行列号,而不能设定棋盘的大小。
实验二动态规划算法(4学时)一、实验目的与要求1、熟悉最长公共子序列问题的算法;2、初步掌握动态规划算法;二、实验题若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。
例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。
给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
递归及递归算法分析课件
A(1,2)=A(A(0,2),1)=A(1,1)=2,故A(n,2)= 2^n 。
2 222
❖ M=3时,类似的可以推出
n
❖ M=4时,A(n,4)的增长速度非常快,以至于没有适当的数 学式子来表示这一函数。
❖
move(a,b);
❖
hanoi(n-1, c, b, a);
❖
}
❖}
❖ T(n)=2T(n-1)+O(1) n≥1
T(n)=2n-1
0
n=0
4
27
简单递归式的求解
1.T(n)=T(n-1)+c1 n>1
c2
n=1
2. T(n)=2T(n/2)+c1 n ≥2
c2
n<2
3. T(n)=2T(n/2)+Θ(n) n ≥2
O(1)
n<2
28
T( n/2 ) + T( n/2 ) + 1
例1 T(n) =
0
(n = 1)
解 :T(n)=2T(n/2)+1
=22T(n/22)+2+1
=23T(n/23)+22+2+1
令2r=n =2rT(1)+2r-1+。。。+2+1
=(1-2r)/(1-2)=n-1
∴ T( n ) = n - 1
25
递归算法的时间复杂度分析
❖ 递归函数求解
简单递归式求解 master method 递推方程的特征方程求解
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2. 排列问题递归算法的描述
2. void perm(Type A[ ], int k, int n) 3. { int i; 5. if (k==1) 6. for (i=0;i<n;i++) // 已构成一个排列,输出它 7. cout << A[ i ]; 8. else { 9. for (i=n-k;i<n;i++) { // 生成后续的一系列排列 10. swap(A[ i ],A[ n-k ]); 11. perm(A,k-1,n); 12. swap(A[ i ],A[ n-k ]); 13. } 14. } 15. }
1
1
3
213 1 2 3
3
231 2
213 231 213 1
3
3 123 213 123
20
排列问题递归算法的求解过程 (续 2)
2. void perm(Type A[ ], int k, int n) i 3. { int i; k 5. if (k==1) n 6. for (i=0;i<n;i++) A的内容 7. cout << A[ i ]; i 8. else { n–k=0 k 9. for (i=n-k;i<n;i++) { n 10. swap(A[ i ],A[ n-k ]); A的内容 11. perm(A,k-1,n); i 12. swap(A[ i ],A[ n-k ]); n–k=0 k 13. } n 14. } A的内容 15. }
算法描述: 7. 8. 9. 10. 11. if (n>0) { insert_sort_rec(A,n-1); a = A[n]; k = n – 1; while ((k>=0)&&(A[k]>a)) {
12.
13. 14. }
A[k+1] = A[k];
k = k - 1;
15.
16. 17. } }
1
1
3
321 1 2 3
3
312 2
321 312 321 2
3
3 123 321 123
21
四 求数组主元素的递归算法
1. 求数组主元素递归算法的思想方法
2. 求数组主元素递归算法的描述
3. 时间复杂性估计
22
1. 求数组主元素递归算法的思想方法
1)数组主元素:
A 是具有 n 个元素的数组,x 是 A 中的一个元素,若 A 中有一半以上的元素与 x 相同,就称 x 是数组的主元素。
有: f ( n ) g ( k ) k 1 log n 1 ( log n )
11
二 递归算法的例子
4. 多项式求值的递归算法 n 阶多项式:
Pn ( x ) a n x n a n1 x n1 a1 x a0
( ( ( ( ( a n ) x a n 1 ) x a n 2 ) x a n 3 ) x ) x a1 ) x a 0
二 递归算法的例子
1. 计算阶乘函数 n!
阶乘函数可归纳定义为
1 n ! n ( n 1)! n0 n0
递归算法如下:
1. int factorial(int n) 2. { 3. if (n==0) 4. return 1; 5. else 6. return n * factorial(n-1); 7. }
A[k+1] = a;
8
二 递归算法的例子
2. 基于递归的插入排序
算法的时间复杂性可由如下递归方程确定
f (0) 0 f ( n ) f ( n 1) ( n 1)
容易得到:
1 f (n) ( i 1) i n ( n 1) 2 i 1 i 1
n
第四章 递归和分治
4.1 基于归纳的递归算法 4.2 分治法
1
4.1 基于归纳的递归算法
一 基于归纳的递归算法的思想方法 二 递归算法的例子 三 排列问题的递归算法 四 求数组主元素的递归算法
五 整数划分问题的递归算法
2
一 归纳法的思想方法
解规模为 n 的问题 P(n): 1. 基础步: a1 是问题 P(1) 的解 2. 归纳步:对所有的 k ,1 < k < n,若 ak 是问题 P(k) 的 解,则 p (ak ) 是问题 P(k+1) 的解,其中,p (ak ) 是对 ak 的某种运算或处理 为求问题 P(n) 的解 an ,先求问题 P(n – 1) 的解 an-1,再对 an-1 进行 p (an-1) 运算或处理,得到 an 为求问题 P(n – 1) 的解 an-1 ,先求问题 P(n – 2) 的解 an-2 再进行 p (an-2 ) 运算或处理,得到 an-1 如此等等,不断地进行递归求解,直到 P(1) 的解 a1为止 当得到 P(1) 的解之后,再回过头来,不断地把所得到的解 3 进行 p 运算或处理,直到得到 P(n) 的解为止
6
二 递归算法的例子
2. 基于递归的插入排序
算法描述: 1. template <class Type>
2. void insert_sort_rec(Type A[ ],int n)
3. { 4. 5. 6. int k; Type a; n = n – 1;
7
二 递归算法的例子
2. 基于递归的插入排序
例:数组 A={1,3,2,3,3,4,3} 中,
元素 3 是该数组的主元素
23
1. 求数组主元素递归算法的思想方法
2)数组主元素性质:
⑴ 移去数组中两个不同元素后,如果原来数组中有主元 素,该主元素仍然是新数组的主元素。 ⑵ 如果数组 2k 个元素中有 k 个元素相同,那么,移去 这 2k 个元素后,如果原来数组中有主元素,该主元 素仍然是新数组的主元素。 ⑶ 对数组不断施加上述两种操作,最后将得到如下结果: ① 新数组只剩下一个元素:该元素可作为主元素的候 选者。 ② 新数组是若干个相同的元素:该元素可作为主元素 的候选者。 ③ 没剩余元素:原来数组没有主元素
4
二 递归算法的例子
1. 计算阶乘函数 n!
算法的时间复杂性可由如下递归方程确定:
f (0) 0 f ( n ) f ( n 1) 1
解此方程,有:
f (n) n (n)
5
二 递归 1)基础步:当 n=1 时,数组只有一个元素,它已经是排 序的; 2)归纳步:如果前面 k-1 个元素已经按递增顺序排序,只 要对第 k 个元素逐一与前面 k-1 个元素比较,把它插入 适当的位置,即可完成 k 个元素的排序
5.
6. 7.
p = A[0];
else p = horner_pol(x,A,n-1) * x + A[n];
8.
9. }
return p;
13
二 递归算法的例子
4. 多项式求值的递归算法 把第7行的乘法作为基本操作,算法的时间复杂性由如下的 递归方程确定:
f (0) 0 f ( n ) f ( n 1) 1
1)基础步:n=0,有 p 0 a n ;
2)归纳步:对任意的 k,1≤k≤n,如果前面 k-1 步已计 算出 p k 1 ,则有: pk x pk 1 an k 把 an 存放于 A[0],a n 1存放于 A[1],如此等等
12
二 递归算法的例子
4. 多项式求值的递归算法 1. float horner_pol(float x,float A[ ],int n) 2. { 3. 4. float p; if (n==0)
可得: f ( n ) ( n )
14
三 排列问题的递归算法
1. 排列问题递归算法的思想方法
2. 排列问题递归算法的描述
3. 排列问题递归算法的求解过程
15
1. 排列问题递归算法的思想方法
存放于数组 A 的 n 个元素,生成其排列的步骤: 1)第一个元素不动,生成后面 n – 1 个元素的排列 2)第一、第二个元素互换,生成后面 n – 1 个元素的排列 3)最后,第一个、第 n 个元素互换,生成后面 n – 1 个元 素的排列;
18
3. 排列问题递归算法的求解过程
2. void perm(Type A[ ], int k, int n) i 3. { int i; k 5. if (k==1) n 6. for (i=0;i<n;i++) A的内容 7. cout << A[ i ]; i 8. else { n–k=1 k 9. for (i=n-k;i<n;i++) { n 10. swap(A[ i ],A[ n-k ]); A的内容 11. perm(A,k-1,n); i 12. swap(A[ i ],A[ n-k ]); n–k=0 k 13. } n 14. } A的内容 15. }
24
1. 求数组主元素递归算法的思想方法
3)思想方法: 假定寻找主元素候选者的算法为 dandidate(Type A[ ],int n,int m) n:数组元素个数,m:数组前面被移去的元素个数, ⑴ 基础步: ① n-m=0:没有主元素候选者 ② n-m=1:A[m] 是主元素候选者,或者: ③ A[m] ~ A[n-1] 是同一元素:A[m] 是主元素候选者 ⑵ 归纳步: ① 据性质 1 移去 A[m] ~ A[n+1] ,用 dandidate(A,n,m+2) 寻找主元素候选者,或者: ② 据性质2 移去 A[m] ~ A[n+2k-1] ,k<(n-m)/2,用 dandidate(A,n,m+2k) 寻找主元素候选者。