第九章 递归

合集下载

递归的工作原理

递归的工作原理

递归的工作原理
递归是一种通过调用自身来解决问题的方法。

它通过将一个大问题分解为较小的、同类的子问题来进行求解。

递归的工作原理可以概括为以下几个步骤:
1. 定义基准情况:递归函数首先需要定义一个基准情况,即最简单的情况,该情况下可以直接给出结果,而不是再次调用自身。

基准情况通常是在满足某个条件时返回固定值或特定操作。

2. 分解问题:递归函数会将给定的问题分解为更小的同类子问题。

这个过程可以通过递归调用本身来实现。

每次递归调用时,问题的规模都会减小,同时保持相同的问题类型。

3. 调用递归函数:递归函数在解决子问题时通过调用自身来实现。

通过递归调用,问题将会在不断分解和缩小的过程中得到解决。

4. 组合结果:递归函数返回的结果会被用来组合成大问题的解。

递归函数返回的结果通常会在每一层递归结束后进行合并、计算或其他操作。

5. 终止递归:为了防止递归无限循环,递归函数需要在某个条件下终止递归调用。

这个条件通常和基准情况或问题规模相关,当满足条件时,递归将停止执行。

需要注意的是,递归函数的设计需要保证每次递归调用后问题规模都会减小,否则递归可能会陷入无限循环,导致程序运行
出错或引起栈溢出。

此外,递归可能会造成重复计算,因此可以采用记忆化搜索等方法进行优化。

递归

递归


编程思路

采用实例3-3的递归产生10位二进制数的全 排列,每位二进制数码分别对应一个问题 的解答情况,0代表答错,1代表回答正确。 若计算出的分数恰好为100,则就是问题的 一组解。
【实例3-5】取值组合

有一个集合拥有m个元素{1,2,…,m}, 任意的从集合中取出n个元素,则这n个元 素所形成的可能子集有哪些?编写一个程 序,输入整数m和n,输出m个元素中,取 出n个元素的各种情况。
使用递归的典型情况
Biblioteka 递归方法通过函数调用自身将问题转化为 本质相同但规模较小的子问题,是分治策 略的具体体现。 递归使用情形

问题的定义是递归的 数据结构是递归的 问题的求解过程是递归的
递归模型


递归模型由递归出口和递归体两部分组成, 前者确定递归到何时结束,后者确定递归 求解时的递推关系 递归的思路是把一个不能或者不好直接求 解的“大问题”转化为一个或者几个“小 问题”来解决;“小问题”进一步分解为 更小的“小问题”;如此分解,直到“小 问题”可以直接求解
将步骤1和步骤2中的递归关系与边界统一起来用数学语 言来表示,即 n!= n*(n−1)! 当n>1时 n!= 1 当n=1时 再将这种关系翻译为代码,即一个函数:
long f(int n){ long g; if (n<0) cout << "n<0, 输入错误!"; else if (n == 1) g = 1; else g = n*f(n-1); return g; }
1 2 3 N 木桩A 木桩B 1 2 3 N 木桩A 木桩B 木桩C 木桩C
编程思路

设递归函数hanoi(n,a,b,c)展示把n个盘从A 柱借助B柱移到C柱的过程

第九章 递归

第九章 递归

Hanoi( n-1,c,b,a); }
汉诺塔问题
void main( ) { int N; cout << "Please input disc number: " << endl; cin >> N; cout << "The solution is:" << endl; Hanoi( N,'A','B','C'); }
//先将n 个盘子, //先将n-1个盘子,以b为中转,从a柱移动到c柱, 先将 为中转, 柱移动到c
Hanoi( n-1,a,c,b);
//将一个盘子从a移动到b //将一个盘子从a移动到b 将一个盘子从
cout << a << "->" << b << endl;
//将 柱上的n 个盘子, //将c柱上的n-1个盘子,以a为中转,移动到b柱 为中转,移动到b
逆波兰表达式
问题描述
–逆波兰表达式是一种把运算符前置的算术表达式,例如2+3 逆波兰表达式是一种把运算符前置的算术表达式,例如2+3 逆波兰表达式是一种把运算符前置的算术表达式 的逆波兰表示法为+ 3。 的逆波兰表示法为+ 2 3。 –逆波兰表达式的优点是运算符之间不必有优先级关系,也 逆波兰表达式的优点是运算符之间不必有优先级关系, 逆波兰表达式的优点是运算符之间不必有优先级关系 不须用括号,例如(2+3)*4的逆波兰表示法为* (2+3)*4的逆波兰表示法为 4。 不须用括号,例如(2+3)*4的逆波兰表示法为* + 2 3 4。 –输入并求解逆波兰表达式的值,其中运算符包括+ - * /。 输入并求解逆波兰表达式的值,其中运算符包括+ /。 输入并求解逆波兰表达式的值

数据结构之递归

数据结构之递归

数据结构之递归Ⅲ递归的三⼤要素// 算 n 的阶乘(假设n不为0)int f(int n){if(n <= 2){return n;}}第三要素:找出函数的等价关系式第三要素就是,我们要不断缩⼩参数的范围,缩⼩之后,我们可以通过⼀些辅助的变量或者操作,使原函数的结果不变。

例如,f(n) 这个范围⽐较⼤,我们可以让 f(n) = n * f(n-1)。

这样,范围就由 n 变成了 n-1 了,范围变⼩了,并且为了原函数f(n) 不变,我们需要让 f(n-1) 乘以 n。

说⽩了,就是要找到原函数的⼀个等价关系式,f(n) 的等价关系式为 n * f(n-1),即f(n) = n * f(n-1)。

这个等价关系式的寻找,可以说是最难的⼀步了,如果你不⼤懂也没关系,因为你不是天才,你还需要多接触⼏道题,我会在接下来的⽂章中,找 10 道递归题,让你慢慢熟悉起来。

找出了这个等价,继续完善我们的代码,我们把这个等价式写进函数⾥。

如下:// 算 n 的阶乘(假设n不为0)int f(int n){if(n <= 2){return n;}// 把 f(n) 的等价操作写进去return f(n-1) * n;}⾄此,递归三要素已经都写进代码⾥了,所以这个 f(n) 功能的内部代码我们已经写好了。

这就是递归最重要的三要素,每次做递归的时候,你就强迫⾃⼰试着去寻找这三个要素。

还是不懂?没关系,我再按照这个模式讲⼀些题。

有些有点⼩基础的可能觉得我写的太简单了,没耐⼼看?少侠,请继续看,我下⾯还会讲如何优化递归。

当然,⼤佬请随意,可以直接拉动最下⾯留⾔给我⼀些建议,万分感谢!Ⅲ案例1:斐波那契数列斐波那契数列的是这样⼀个数列:1、1、2、3、5、8、13、21、34....,即第⼀项 f(1) = 1,第⼆项 f(2) = 1.....,第 n 项⽬为 f(n) = f(n-1) + f(n-2)。

求第 n 项的值是多少。

递归 高等数学

递归 高等数学

递归与高等数学一、递归函数递归函数是一种数学函数,它在其定义或行为中直接或间接地调用自身。

递归函数通常用于解决一些可以分解为更小的子问题的问题。

递归函数可以分为两类:基本递归函数和递归函数。

基本递归函数是直接解决问题的函数,而递归函数则是通过调用自身来解决问题的函数。

在高等数学中,许多问题可以通过使用递归函数来解决。

例如,在微积分中,许多积分和级数可以通过递归方法进行计算。

此外,在实数和复数分析中,许多函数可以通过递归函数进行展开和逼近。

二、递归数列递归数列是一种特殊的数列,它可以通过一系列规则生成。

常见的递归数列包括斐波那契数列、卢卡斯数列等。

递归数列在数学和计算机科学中都有广泛的应用。

在高等数学中,递归数列可以用于解决一些与序列相关的问题。

例如,在概率论和统计学中,一些概率分布可以通过递归数列进行描行解决。

三、递归方程递归方程是一种描述自然规律的数学工具,它是通过递归函数定义的等式或系统。

常见的递归方程包括人口动态模型、斐波那契序列等。

在高等数学中,递归方程可以用于解决一些与时间相关的问题。

例如,在微分方程和差分方程中,一些问题可以通过递归方程进行描述和解决。

此外,在控制理论和系统理论中,一些系统可以通过递归方程进行建模和分析。

四、递归级数递归级数是具有特定模式的数字序列或数字集的级数表示。

它与级数、级数定理、积分级数以及算术、几何和三角级数等都有密切的关系。

在高等数学中,递归级数可以用于解决一些与数字相关的问题。

例如,在离散概率论和统计学中,一些概率分布可以通过递归级数进数进行解决。

五、递归图论图论是研究图(由顶点和边构成的图形)的数学理论。

在图论中,图是由顶点(或节点)和连接这些顶点的边构成的。

递归图论则是使用递归来定义或描述图的理论。

在计算机科学中,这可以用于计算机算法、数据结构和其他相关的领域。

例如,一种常用的数据结构是二叉堆(Binary Heap),它可以看作是一个完全二叉树,并且每个节点都有两个子节点(除了叶节点)。

递归

递归

递归实例4
循环日程表问题。 n=8个运动员的日程表,填充方式见下面
一个8*8(23的方阵) 的矩阵,可以分为4*4(22的方阵)的 四个矩阵,设其分别A,B,C,D,则A=B,C=D=A+4
递归实例4
循环日程表问题
void circulateSchedule(int n) { // 递归出口 if(n == 1) { return ; } // 将2^k*2^k的表格分成2^(k-1)*2^(k-1)的四个子表格,构造第1个子表 int half = n / 2; circulateSchedule( half); // 填充余下三个子表 for(int i=0; i<half;i++) for(int j=0;j<half;j++) { table[half+i][half+j] = table[i][j]; table[i][ half+j] = table[ half+i][j] = table[i][j] + half; }
“汉诺塔”(Hanoi)
这是一个必须用递归方法才能解决的问题
n=64时, 18,446,744,073,709,551,615次 1844亿亿次 每次1微秒,需要60万年
递归问题分析
第一步:将问题简化。
假设A杆上只有2个圆盘,即汉诺塔有2层,n=
2。 A
B
C
递归问题分析
递归实例3——解决复杂问题
汉诺塔——汉诺塔问题是最经典的只能够使用
递归的方法解决的问题,题目描述如下:
据传说,在古代世界中心的贝拿勒斯(印度北部)的圣庙 里,一块在黄铜 板上插着3根宝石针。印度教的主神梵天 在创造世界时,在其中的一根针上自下而上地穿好了由大 至小的64层金片,即为汉诺塔。无论白天黑夜,总有一个 僧侣按 如下的法则移动这些金片,一次只能够移动一层 ,不管在哪根针上,小片必须在大片的上面。 要求借助 于第二根针将整个汉诺塔移至第三根针上。

数据结构(C++)--递归

数据结构(C++)--递归

数据结构(C++)..递归数据结构(C++)..递归1.什么是递归递归是指在函数的定义中调用函数本身的情况。

通过递归,可以解决一些问题,特别是那些问题的解决方法和问题的子问题的解决方法相同或相似的情况。

递归的思想是将大问题拆分成小问题,然后通过解决小问题来解决大问题。

递归过程中,函数会不断调用自身,直到达到某个终止条件。

2.递归的基本要素●递归函数的定义:递归函数是指在函数中调用自身的函数。

●终止条件:递归函数必须有一个终止条件,以终止递归过程,避免无限递归。

●递归调用:递归函数在函数体中调用自身。

3.递归的实现递归可以用于解决很多问题,例如计算阶乘、斐波那契数列等。

3.1 计算阶乘```cppint factorial(int n) {if (n == 0 .......●n == 1) {return 1。

}return n factorial(n.1)。

}```在上述代码中,计算阶乘的递归函数`factorial`通过调用自身来实现。

当n为0或1时,递归终止,返回1。

否则,递归调用`factorial(n.1)`来计算(n.1)的阶乘,并将结果乘以n。

3.2 斐波那契数列```cppint fibonacci(int n) {if (n == 0 .......●n == 1) {return n。

}return fibonacci(n.1) + fibonacci(n.2)。

}```在上述代码中,计算斐波那契数列的递归函数`fibonacci`通过调用自身来实现。

当n为0或1时,递归终止,返回n。

否则,递归调用`fibonacci(n.1)`和`fibonacci(n.2)`来计算前两个数的和。

4.递归的优缺点4.1 优点●代码简洁:递归能将问题简化成更小的问题,提高代码的可读性和可维护性。

●解决复杂问题:递归能解决一些复杂的问题,例如树的遍历、图的搜索等。

4.2 缺点●递归调用会占用大量的栈空间,导致内存消耗较大。

2017-递归

2017-递归

例. Hanoi塔的迭代算法,m是原柱上圆盘的个数 算法HI(m) HI1[建立堆栈]
CREATS(S). HI2[堆栈初始化]
S(m,1,2,3). HI3[利用栈实现递归]
WHILE NOT(StackEmpty(S))DO ((n, i, j, k) S. IF n = 1 THEN MOVE(i, k) ELSE(S(n-1, j, i, k). S(1, i, j, k).
IF p = NULL THEN ( PRINT “Can not find the item”. RETURN. )
S2. IF data(p) = item THEN Dealwith(p). // 通过Dealwith函数 // 对该节点进行一定的处理 ELSE Search( next(p), item).
void Hanoi (int n, String A, String B, String C ) { //解决汉诺塔问题的算法
if ( n == 1 ) cout << "move" << A << " to " << C << endl;
else { Hanoi ( n-1, A, C, B ); cout << " move " << A << " to " << C << endl; Hanoi ( n-1, B, A, C ); }
最后一次发生的递归过程必须最先完成。
例. 计算数组 A 中最大最小元素的算法BS 。 算法BS(A ,i ,j . fmax ,fmin) /* 在数组A的第i个元素到第j个元素之间寻找最大和
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

15
递归设计步骤
(1)对原问题f(s)进行分析,假设出 合理的“较小问题” f(s’); (2)假设f(s’)是可解的,在此基础 上确定f(s)的解,即给出f(s)与f(s’) 的关系; (3)确定一个特定情况(f(1)或f(0)) 的解,由此作为递归出口。
16
递归到非递归的转换
求解递归问题有两种方法: 1、直接求值,不需要回溯的(单向递归和 尾递归):使用一些中间变量保存中间结 果;
void sterfunc ( int A[ ], int n ) { //消除了尾递归的非递归函数 while ( n >= 0 ) { printf( "value %d" , A[n] ); n--; } }
21
递归到非递归的转换 ——间接转换法


间接转换法一般的过程如下:
将初始状态s0进栈 while (栈不为空) { 退栈,将栈顶元素赋给s if (s是要找的结果) 返回 else { 寻找到s的相关状态s1 将s1进栈 } }
第九章 递归
[内容提要] 1、递归的概念及设计方法 2、递归与回朔法 3、递归应用实例 4、递归评价
递归的定义
若一个对象部分地包含它自己, 或用它自己给自己定义, 则称这个对 象是递归的;若一个过程直接地或间 接地调用自己, 则称这个过程是递归 的过程。
2
递归的定义
直接递归 fun_a() { … fun_a() … }

11
递归模型
例如,阶乘函数 递归出口
1, 当n 0 时 n! n (n 1)!, 当 n 1时
递归体
12
递归的执行过程
实际上,递归是把一个不能或不好 直接求解的“大问题”转化为一个或 几个“小问题”来解决,再把这些 “小问题”进一步分解成更小的“小 问题”来解决,如此分解,直至每一 个“小问题”都可以直接解决(此时 分解到递归出口)。
A
B
C
1 C A B 8 2 A C B 6 0 3 A B C
A
B 6 0
C
2 A C B 3 A B C
3 A B C
0
30
main() 3 A B C 0 { int m; printf("Input the number of disks scanf("%d",&m); printf("The steps to moving %3d hanoi(m,'A','B','C'); (0) } void hanoi(int n,char x,char y,char z) (1) { (2) if(n==1) (3) move(1,x,z); (4) else{ (5) hanoi(n-1,x,z,y); (6) move(n,x,z); (7) hanoi(n-1,y,x,z); (8) } (9) }
23
回朔法
回溯法在用来求问题的所有解时,要回 溯到根,且根结点的所有子树都已被搜索 遍才结束。而回溯法在用来求问题的任一 解时,只要搜索到问题的一个解就可以结 束。这种以深度优先的方式系统地搜索问 题的解的算法称为回溯法。
24
递归与回朔的区别——指导思想
回溯法是从问题的某一种可能出发, 搜索从这种情况出发所能达到的所有 可能,当这一条路走到“尽头”的时 候,再倒回出发点,从另一个可能出 发,继续搜索。
9
递归模型
递归模型反映一个递归问题的递归结构。 一般地,一个递归模型是由递归出口和递归 体两部分组成,前者确定递归到何时为止, 后者确定递归的方式。
10
递归模型
递归出口的一般格式为: f(s0)=m0;这里的s0与m0均为常量,有的递归问 题可能有几个递归出口。 递归体的一般格式为: f(s)=g(f(s1), f(s2),……, f(sn),c1, c2,……, cm) 这里的s是一个递归“大问题”,s1, s2,……, sn是递归“小问题”,c1, c2,……,cm是若干 个可以直接(用非递归方法)解决的问题,g是 一个非递归函数,反映了递归问题的结构。
4
适用递归技术的问题

以下三种情况常常用到递归方法。 – 定义是递归的 – 数据结构是递归的 – 问题的解法是递归的
5
定义是递归的
例如,阶乘函数 1, 当n 0 时 n! n (n 1)!, 当 n 1时 求解阶乘函数的递归算法 long Factorial ( long n ) { if ( n == 0 ) return 1; else return n * Factorial (n-1); }
22
回朔法
回溯法是一个既带有系统性又带有跳跃性的 的搜索算法。它在包含问题的所有解的解 空间树中,按照深度优先的策略,从根结 点出发搜索解空间树。算法搜索至解空间 树的任一结点时,总是先判断该结点是否 肯定不包含问题的解。如果肯定不包含, 则跳过对以该结点为根的子树的系统搜索, 逐层向其祖先结点回溯。否则,进入该子 树,继续按深度优先的策略进行搜索。
26
递归技术应用实例——汉诺塔问题
例如,汉诺塔(Tower of Hanoi)问题的解法: 如果 n = 1,则将这一个盘子直接从 A 柱移到 C 柱上。否则,执行以下三步: ① 用 C 柱做过渡,将 A 柱上的 (n-1) 个盘子移 到 B 柱上: ② 将 A 柱上最后一个盘子直接移到 C 柱上; ③ 用 A 柱做过渡,将 B 柱上的 (n-1) 个盘子移 到 C 柱上。
13
求解阶乘 n! 的过程
主程序 main : fact(4) 参数 4 递 归 调 用 参 数 传 递 计算 4*fact(3) 返回 24
参数 3
参数 2 参数 1 参数 0
计算 3*fact(2)
计算 2*fact(1) 计算 1*fact(0) 直接定值 = 1
返回 6
返回 2 返回 1 返回 1
1 2 3 A
B 0
C
3 A B C
2 A C B
3 A B C 1 A B C 2 A C B
6
0 6 6
3 A B C
0
A
B 6 0
C
2 A C B C B 6 { int m; 3 A B C 0 printf("Input the number of disks scanf("%d",&m); printf("The steps to moving %3d hanoi(m,'A','B','C'); (0) } void hanoi(int n,char x,char y,char z) (1) { (2) if(n==1) (3) move(1,x,z); (4) else{ (5) hanoi(n-1,x,z,y); (6) move(n,x,z); (7) hanoi(n-1,y,x,z); (8) } (9) }
结 果 返 回
回 归 求 值
14
递归设计
递归设计先要给出递归模型,再转换成对应 的C语言函数。从递归的执行过程看,要解决 f(s),不是直接求其解,而是转化为计算f(s’) 和一个常量c’,求解f(s’)的方法与环境和求解 f(s)的方法与环境是相似的,但f(s)是一个“大 问题”,而f(s’)是一个“较小问题”,尽管f(s’) 还未解决,但向解决目标靠近了一步,这就是一 个“量变”,如此到达递归出口,便发生了“质 变”,递归问题解决了。
18
递归到非递归的转换 ——直接转换法
long FibIter ( long n ) { if ( n <= 1 ) return n; long twoback=0, oneback = 1, Current; for ( int i = 2; i <= n; i++ ) { Current = twoback + oneback; twoback=oneback; oneback = Current; } return Current; }
19
递归到非递归的转换 ——直接转换法
25 36 72 18 99 49 54 63
void recfunc ( int A[ ], int n ) { if ( n >= 0 ) { printf(“%d ”,A[n]); n--; recfunc ( A, n );//尾递归 } }
20
递归到非递归的转换 ——直接转换法
A
B
C
2 B A C
3 A B C
8
0
1 B C A 6
2 B A C
3 A B C
8
0
A
B 8
C
2 B A C
3 A B C
0
31
main() 2 B A C 8 { int m; 3 A B C 0 printf("Input the number of disks scanf("%d",&m); printf("The steps to moving %3d hanoi(m,'A','B','C'); (0) } void hanoi(int n,char x,char y,char z) (1) { (2) if(n==1) (3) move(1,x,z); (4) else{ (5) hanoi(n-1,x,z,y); (6) move(n,x,z); (7) hanoi(n-1,y,x,z); (8) } (9) }

2、不能直接求值,需要回溯的:用栈来保 存中间结果。
17
递归到非递归的转换 ——直接转换法
相关文档
最新文档