第五章、递归
大一c语言章节知识点
大一c语言章节知识点第一章:基本概念和数据类型C语言的历史背景C语言的特点和优势关键字和标识符数据类型及其表示范围变量的定义和声明常量的定义和分类运算符的分类和优先级第二章:运算符和表达式算术运算符和表达式逻辑运算符和表达式位运算符和表达式赋值运算符和表达式关系运算符和表达式条件运算符和表达式运算符的优先级和结合性第三章:控制语句顺序结构选择结构(if语句、switch语句)循环结构(for循环、while循环、do-while循环)循环控制语句(break、continue、goto)嵌套控制语句第四章:数组和字符串数组的定义和初始化数组的访问和操作多维数组字符数组和字符串的处理字符串的输入和输出第五章:函数和递归函数的调用和返回函数的参数传递(值传递、地址传递)递归函数的原理与应用递归和迭代的比较第六章:指针指针的定义和声明指针与数组的关系指针的运算(指针的加减、指针的比较)指针与字符串的处理函数指针和指针数组第七章:结构体和共用体结构体的定义和初始化结构体中成员的访问和操作结构体的嵌套和对齐枚举类型的定义和应用第八章:文件操作文件的打开和关闭文件的读写操作(字符型文件、二进制文件)文件指针的位置控制文件的随机访问和更新第九章:动态内存管理内存分配与释放的概念malloc函数和free函数的使用calloc函数和realloc函数的使用动态分配二维数组的操作第十章:预处理指令宏定义的使用条件编译指令的应用文件包含指令的作用错误指示和行控制指令无论是在学习C语言的过程中,还是在实际应用中,以上这些章节知识点都是非常重要的。
掌握这些知识点,将帮助你深入了解C语言的基本原理和常用功能,为编写高效、健壮的程序奠定扎实基础。
在学习过程中,请务必理解并实践每个章节的知识点,并结合实际案例进行练习和应用,以加深对C语言的理解和应用能力。
祝你在学习C语言的道路上取得优异的成绩!。
第5章-递归(高级程序设计)
f(n)=
将n-1个盘从一针移到另一针上 n>1
例 Hanoi问题
A
B
void move(char getone, char putone) { printf("%c--->%c\n",getone,putone); } void hanoi(int n,char one,char two,char three) { if(n==1) move(one,three); else C { hanoi(n-1,one,three,two); move(one,three); hanoi(n-1,two,one,three); } } main() { int m; printf("Input the number of disks:"); scanf("%d",&m); printf("The steps to moving %3d disks:\n",m); hanoi(m,'A','B','C'); }
6.2递归算法及其执行过程
(1)用于某些概念的定义: 阶乘: if ( n>0 ) n ! = n ( n-1 ) ! if ( n=0 ) n ! = 1 单链表结点:
struct node{ datatype data struct node * Link;
} 二叉树:二叉树是数据元素的有穷集合,它或者为空集 (空二叉树),或者由一个根元素和其下的两棵互不相交
6.4 递归过程与运行时栈
为了保证递归调用的正确性,需要保存调用点的现场(返回地 址、局部变量、被调用函数的参数等),以便正确地返回,并且按 先进后出的原则来管理这些信息。在高级语言(编译程序)中,是 通过利用“递归工作栈”来实现递归调用的。 f(n) f(n-1) f(n-2) f(1) f(0)
第五讲递推与递归PPT课件
开始,每1项等于前面3项的和。
f(n)=f(n-1)+f(n-2)+f(n-3)-----递推公式 f(1)=1 , f(2)=2 , f(3)=4 --------递推边界
27
① #include <stdio.h> //上楼问题
② void main( )
③ { int x,n,i,a,b,c;
3)第二只猴子醒来,又把桃子均分成五堆后,还是多了一 个,它也吃掉这个桃子,并拿走了其中一堆。
第三只,第四只,第五只猴子都依次如此分食桃子。 问:五只猴子采得一堆桃子数最少应该有几个呢?
11
例2:猴子分食桃子---逆推法
算法分析:
先要找第N只猴子和其面前桃子数的关系。如 果从第1只开始往第5只找,不好找,但如果思路 一变,从第N到第1去,可得出下面的推导式:
19
例11.2 骨牌问题---顺推法
➢长度为n时的骨牌铺放方案? ➢从最简单的情况开始寻找问题解决的规律?--- 顺推 ➢以 f(i) 表示n=i时的铺放方案数目。 ➢当n=1时,只有1种铺法,即f(1)=1,如下左图所示: ➢当n=2时,只有2种铺法,即f(2)=2,如下右图所示。
20
例11.2 骨牌问题---顺推法
n=1
f(n)=1
n=2
f(n)=2
n=3
f(n)=3
n=4
f(n)=3 + 1 =f[3]+ f[1]=4
n=5
f(n)=f(4)+f(2)
n=6
f(n)=f(5)+f(3)
n=7
f(n)=f(6)+f(4)
规律: f(n)=f(n-1)+f(n-3) (n>=4) 17
数据结构课件第5章递归
return fact; }
递归调用执行情况如下:
int fact (int w) {1if ( w==0) 2 fact= 1; 3else 4fact=w* fact( w-1); }
递归思路
实际上, 递归思路是把一个不能或不好直接求解 的“大问题”转化成一个或几个“小问题”来解决, 再把这些“小问题”进一步分解成更小的“小问题” 来解决,如此分解,直至每个“小问题”都可以直接解 决(此时分解到递归出口)。
但递归分解不是随意的分解,递归分解要保证“大 问题”与“小问题”相似,即求解过程与环境都相似。 并且有一个分解的终点。从而使问题可解。
假 设 f(A,i-1) 已 求 出 , 则 f(A,i)=MIN(f(A,i1),A[i]),其中MIN()为求两个值较小值函数。因 此得到如下递归模型:
A[0] 当i=0时 f(A,i)=
MIN(f(A,i-1),A[i]) 其他情况
由此得到如下递归求解算法:
float f(float A[],int i) { float m;
n!
n
1, (n 1)!,
当n 0时 当n 1时
该问题的算法为: int Fact ( int n )
{ int m; if (n= =0) return(1); else { m=n*Fact(n-1); return(m); } }
例如: 试编一个递归函数,求第n项Fibonacci级数的
} } // delete
5.3 递归算法到非递归算法的转换
递归算法有两个基本特性:一是递 归算法是一种分而治之的、把复杂问 题分解为简单问题的求解问题方法,对 求解某些复杂问题,递归算法分析问题 的方法是十分有效的;二是递归算法 的时间/空间效率通常比较差。
《C语言程序设计教程》第三版课后习题参考答案
《C语言程序设计教程》第三版课后习题参考答案C语言程序设计教程第三版课后习题参考答案第一章:C语言概述1.1 C语言的特点答案:C语言是一种通用的、面向过程的程序设计语言,具有高效、简洁、灵活等特点。
它提供了丰富的程序设计元素和功能,适用于各种不同的应用领域。
1.2 C语言程序的基本结构答案:C语言程序由预处理指令、函数声明、函数定义、变量声明和语句组成。
其中,预处理指令用来引入头文件或定义宏,函数声明用来声明函数的名称和参数,函数定义用来实现函数的功能,变量声明用来声明变量的类型和名称,语句用来表达具体的计算过程。
1.3 C语言的数据类型答案:C语言提供了多种数据类型,包括基本类型(整型、浮点型、字符型等)和派生类型(数组、指针、结构体等)。
每种数据类型在内存中占据一定的存储空间,并具有特定的取值范围和操作规则。
1.4 C语言的运算符和表达式答案:C语言支持各种运算符和表达式,例如算术运算符(+、-、*、/等)、关系运算符(>、<、==等)、逻辑运算符(&&、||、!等)等。
通过运算符和表达式可以进行各种数值计算和逻辑判断。
第二章:基本数据类型与运算2.1 整型数据类型答案:C语言提供了不同长度的整型数据类型,包括有符号整型(int、long等)和无符号整型(unsigned int、unsigned long等)。
整型数据类型可以表示整数值,并具有不同的取值范围。
2.2 浮点型数据类型答案:C语言提供了浮点型数据类型(float、double等),用来表示带小数部分的实数值。
浮点型数据可以表示较大或较小的数值,并具有一定的精度。
2.3 字符型数据类型答案:C语言提供了字符型数据类型(char),用来表示单个字符。
字符型数据可以用于表示各种字符(包括字母、数字、符号等)。
2.4 布尔型数据类型答案:C语言不直接支持布尔型数据类型,但可以使用整型数据类型来表示布尔值(0表示假、非零表示真)。
python课件第五章Python的函数:函数的递归及应用
教学内容
5.5 函数的递归
5.7 内置函数
教学要求
掌握:函数的嵌套与递归。 熟悉:函数的概念、函数化编程的思想。 了解:内置函数的使用。
5.5 函数的递归
函数定义中调用函数自身的方式形成递归。
例5-4 求第n项的阶乘
阶乘一般定义:n!=n(n-1)(n-2)……(1)
2022/2/3
17
5.7 Python内置函数
2022/2/3
18
5.7 Python内置函数
2022/2/3
19
5.7 Python内置函数
2022/2/3
20
小结
掌握:函数的定义和使用;函数的参数和 函数的返回值;函数的嵌套。
熟悉:函数的递归。 了解:内置函数的使用。
课堂小测
单选题 1分
n!=
n(n-1)! (n>0)
2022/2/3
5
5.5 函数的递归
例5-4 求第n项的阶乘
2022/2/3
6
ห้องสมุดไป่ตู้
5.5 函数的递归
执 行 过 程
2022/2/3
7
多选题 1分
下列是递归程序特点的是()。
A 书写简单 B 一定要有基例 C 执行效率高 D 思路简单,但不宜理解
提交
5.5 函数的递归
例5-5 科赫曲线的绘制
2022/2/3
9
5.5 函数的递归
例5-5 科赫曲线的绘制——实验七(见实验课件)
2022/2/3
10
课后思考:汉诺塔问题
问题IPO 输入:汉诺塔的层数 处理:实现一个汉诺塔圆盘的移动,采用递归实现将所有圆盘从A移 动到C。 输出:整个移动流程
递归算法详解完整版
递归算法详解标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N]递归冯文科一、递归的基本概念。
一个函数、概念或数学结构,如果在其定义或说明内部直接或间接地出现对其本身的引用,或者是为了描述问题的某一状态,必须要用至它的上一状态,而描述上一状态,又必须用到它的上一状态……这种用自己来定义自己的方法,称之为递归或递归定义。
在程序设计中,函数直接或间接调用自己,就被称为递归调用。
二、递归的最简单应用:通过各项关系及初值求数列的某一项。
在数学中,有这样一种数列,很难求出它的通项公式,但数列中各项间关系却很简a与前面临近几项之间的关单,于是人们想出另一种办法来描述这种数列:通过初值及n系。
要使用这样的描述方式,至少要提供两个信息:一是最前面几项的数值,一是数列间各项的关系。
比如阶乘数列1、2、6、24、120、720……如果用上面的方式来描述它,应该是:a的值,那么可以很容易地写成这样:如果需要写一个函数来求n这就是递归函数的最简单形式,从中可以明显看出递归函数都有的一个特点:先处理一些特殊情况——这也是递归函数的第一个出口,再处理递归关系——这形成递归函数的第二个出口。
递归函数的执行过程总是先通过递归关系不断地缩小问题的规模,直到简单到可以作为特殊情况处理而得出直接的结果,再通过递归关系逐层返回到原来的数据规模,最终得出问题的解。
以上面求阶乘数列的函数)f为例。
如在求)3(f时,由于3不是特殊值,因此需(n要计算)2(3f,但)2(f是对它自己的调用,于是再计算)2(f,2也不是特殊值,需要计*算)1(f,返回)1(= 2f,需要知道)1(f的值,再计算)1(f,1是特殊值,于是直接得出1*上一步,得23*)2()3(==f,从而得最终=f)1(32**)2(==f2f,再返回上一步,得6解。
用图解来说明,就是下面再看一个稍复杂点的例子。
【例1】数列}{n a 的前几项为1、111+、11111++、1111111+++、……输入n ,编程求n a 的精确分数解。
《数据结构与算法》PPT课堂课件-第5章-递归
(2) if(n==1)
(3) move(x,z);
(4) else{
(5)
hanoi(n-1,x,z,y);
(6)
move(x,z);
(7)
hanoi(n-1,y,x,z);
(8) }
(9) }
A
B
C
2BAC 8 3ABC 0
1BCA6 2BAC 8 3ABC 0
A
B
C
2BAC 8 3 A B C 0 15
O(n)。对比循环结构的Fib2(n)和递归结构的Fib(n)可发现,循环结构
的Fib2(n)算法在计算第n项的斐波那契数列时保存了当前已经计算得到
的第n-1项和第n-2项的斐波那契数列,因此其时间复杂度为O(n);而递
归结构的Fib(n)算法在计算第n项的斐波那契数列时,必须首先计算第n -1项和第n-2项的斐波那契数列,而某次递归计算得出的斐波那契数列, 如Fib(n-1)、Fib(n-2)等无法保存,下一次要用到时还需要重新递归计
{ printf(“参数错!”);
return -1;
}
if(n == 0) return 1;
else {y = Fact(n - 1); /*递归调用*/
return n * y; }
}
5
为说明该递归算法的执行过程,设计主函数如下
void main(void) {
long int fn;
fn = Fact(3); }
(1) {
(2) if(n= =1)
(3) move(x,z);
(4) else{
(5)
hanoi(n-1,x,z,y);
(6)
move(x,z);
数据结构 第5章_递归
2 m=Fibona(2)+Fibona(1); 1 return(m);
(13)
1
(15)
S3
(8) 2
m=Fibona(2)+Fibona(1);
(9)
(10)
1
(14)
return(1)
return(m);
return(1)
return(1)
(4)
return(1)
(5) 1
(6)
(7) 1 Fibona(5)的执行过程
退出
5.3 递归程序到非递归程序的转换
采用递归方式实现问题的算法程序具有结构清 晰、可读性好、易于理解等优点,但递归程序较之 非递归程序无论是空间需求还是时间需求都更高, 因此在希望节省存储空间和追求执行效率的情况下, 人们更希望使用非递归方式实现问题的算法程序; 另外,有些高级程序设计语言没有提供递归的 机制和手段,对于某些具有递归性质的问题(简称 递归问题)无法使用递归方式加以解决,必须使用 非递归方式实现。因此,本小节主要研究递归程序 到非递归程序的转换方法。
退出
例5 采用非递归方式实现求正整数n的阶乘值。 仍使用Fact(n)表示n的阶乘值。要求解Fact(n) 的值,可以考虑i从0开始,依次取1,2,……,一直到n, 分别求Fact(i)的值,且保证求解Fact(i)时总是以前 面已有的求解结果为基础;当i=n 时,Fact(i)的值即 为所求的Fact(n)的值。
退出
排列问题
设计一个递归算法生成n个元素{r1,r2,…,rn}的全排列。
设R={r1,r2,…,rn}是要进行排列的n个元素,Ri=R-{ri}。 集合X中元素的全排列记为perm(X)。 (ri)perm(X)表示在全排列perm(X)的每一个排列前加 上前缀得到的排列。R的全排列可归纳定义如下:
数据结构(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-递归
例. 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.基准条件(基础案例):递归函数需要定义在何时结束递归的条件。
当满足基准条件时,递归将不再进行,而是返回一个最终结果。
2.递归调用:递归函数在处理问题时,会将原问题分解成一个或多个较小的子问题。
为了解决这些子问题,递归函数需要调用自身。
3.问题拆解:递归函数需要根据原问题,将其分解成与原问题类似但规模更小的子问题。
4.合并结果:递归函数需要将子问题的结果合并起来,得到原问题的解。
递归的优缺点递归的优点在于它能够清晰地表达问题的解决思路,简化代码的编写。
在某些问题中,使用递归能够使代码更加简洁易懂。
然而,递归也存在一些缺点。
首先,递归函数的调用过程是逐层深入的,这会占用大量的内存,如果递归的层数过多,可能会导致栈溢出。
此外,递归函数的执行效率通常较低,因为每一次递归调用都会增加函数调用的开销。
递归的应用场景递归算法广泛应用于各种领域,特别是数学、计算机科学和算法设计中。
以下是一些常见的递归应用场景:1.阶乘计算:计算一个正整数的阶乘可以使用递归来实现,如factorial(n) = n * factorial(n-1)。
2.斐波那契数列:斐波那契数列是一个递归定义的数列,其中每一项等于前两项的和。
递归函数可以用来计算斐波那契数列的第 n 项。
3.二叉树遍历:对于二叉树的遍历,可以使用递归来实现前序、中序和后序遍历。
4.文件夹遍历:对于文件夹中的文件和子文件夹,可以使用递归来遍历整个文件目录树。
5.5.1 递归算法与递归函数概述_C语言程序设计案例教程(第2版)_[共2页]
145 〖运行结果〗运行这个程序后,将会产生如下所示的结果。
排序所花费的时间主要消耗在比较和交换操作上,因此,可以认为:比较和交换次数较少的排序算法运行效率较高。
很显然,冒泡排序所需交换的次数依赖于原始数据的排列状态。
如果原始数据排列基本有序,交换次数就少;反之交换次数就多。
另外,从程序中还可以看出,比较操作位于两层for 之中,总共需要进行n (n -1)/2次,这里的执行次数与原始数据的排列顺序无关,甚至当所有数据已经按照升序排列好之后,还是需要将剩余的比较操作进行完毕。
一种改进的方法是:当发现所有数据已经排列好时,立即停止循环。
有兴趣的读者可以思考一下:什么状态表示所有数据已经排好序,并对sort( ) 函数进行修改,以提高冒泡排序算法的运行效率。
5.5 递归算法与递归函数对规模大且复杂度高的问题进行分解是降低求解难度、确保程序质量的一种有效方法。
有很多问题经过分解后会发现子问题的基本结构与原问题完全相同,因此,可以采用求解原问题的基本方法来求解各个子问题。
这种解决问题的思路就是递归。
递归是一种常见的解题方法,掌握递归并了解递归的执行过程是充分利用C 语言编写程序的基本前提。
5.5.1 递归算法与递归函数概述下面先看两个实例,以便说明递归算法的概念。
实例1:计算n 的阶乘。
大家都知道,n 阶乘的数学表达形式是n !,其含义为1×2×3×4…×(n -1)×n 。
从这个数学公式中可以发现,n !可以通过在(n -1)!的基础上再乘上一个n 得到,因此,n !又可以采用下面这种定义形式:n != n ×(n -1)! n ≥1 1 n =0这个定义形式表明:n !等于n 与(n -1)!的乘积。
像这样在定义一个概念的时候又用到自身概念的定义形式被称为递归定义,它直接反映了求解n !的基本过程,即将计算n !的过程分解成n 与(n -1)!的乘积;将计算(n -1)!的过程分解成(n -1)与(n -2)!的乘积;依次类推,直到将计算1!分解成1与0!的乘积为止。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
返本章 上一页
下一页
#include<iostream.h> long fact(long n) { if(n<=1) return 1; else return n*fact(n-1);} void main() { cout<< fact(4); } main() fact(4)
函数递归调用, 各次调用的数据 存放在栈的不同 空间,彼此相互 独立,函数代码 段则回溯法( 试探法):
返本章 上一页
下一页
分治法问题举例
【例】汉诺塔问题: 有三根柱子,A柱上叠放有N个圆盘,这些圆盘自下而 上由大到小叠放在一起。要求将这些圆盘移到C柱上, 且仍然按自下而上由大到小叠放在一起 移动圆盘要遵守如下规则:
每次只能移动一个圆盘 任何时刻都不允许将较大圆盘压在较小圆盘的上面 在满足上述规则的前提下,可在三个柱子之间任意移动圆盘
6
返本章 上一页
下一页
使用系统提供的栈实现的递归过程,实质上是子程序嵌套 调用的特例,即函数嵌套调用自己。常称作递归算法。 其特点是: 不同层次的递归调用,调用的是都是同一段代码(即递 归函数体自身) 但函数每递归调用自己一次,都必须在系统栈中重新分 配一个内存空间(即所谓工作记录),以便存放本层使用 的局部变量和实在参数 显然,不同层次的递归调用,它们的局部变量的变量名 虽然相同,但是作为不同的工作记录的组成部份,存放 在系统栈的不同地方(即内存的不同地方),它们之间是 彼此独立的。 不同层次的局部变量之间可通过实在参数与形式参数进 行数据传递。
12
返本章 上一页
下一页
使用叠代法实现递归过程:
单向递归: 递归函数中,各递归调用语句中的参数只与主调用函数 有关,与其他递归调用语句中的参数无关。 递归调用语句都处于函数的最后 例如求裴波那契数列函数。 尾递归: 递归函数中,递归调用语句只有一个,且处于函数的最 后。 例如阶乘函数 对单向递归或尾递归的递归过程,也可以用叠代方法加以 实现
15
采用用户栈方法的特性:
采用叠代方法的特性:
返本章 上一页
下一页
可利用递归方法实现的算法
分治法:
一个规模较大的问题,若能分解成几个规模较小且解法相 同或相似的子问题 只要求出子问题的解,就能利用子问题的解求得原问题的 解。 称上述解法是分而治之法(分治法)。 递归与分治尤如一双孪生兄弟,经常相伴而行。 将问题的所有候选解按某一顺序逐一枚举和检验。 若发现当前候选解不是问题的解,就放弃当前解,转而寻 求下一个候选解。 称上述解法是回溯法。
9
}
返本章 上一页
下一页
2.
采用用户自定义栈实现递归过程:
递归过程也可通过引入用户自定义的栈模拟系统提供的 栈操作来加以实现。 这种实现不涉及程序的自我调用(即不涉及程序的中断调 用)。也就不涉及断点保护问题。 数据的入栈及出栈操作不是由系统自动完成,而是由用 户通过编码加以实现,通常称为非递归算法。
3* 3*2 fact(2) 2* fact(1) 2*1
8
返本章 上一页
下一页
【例】用系统工作栈求裴波那契数列: #include<iostream.h> long Fib(long n) { if ( n<=1) return n; return Fib( n-1 )+Fib( n-2 ); } void main() { long n; cout<<"Enter number :"; cin>>n; for(int i=0;i<=n;i++) cout<< "Fib(" << i << ")=" << Fib(i) <<endl; 说明: main()调用Fib(),称作外部调用 Fib()自己调用自己称作内部调用
汉诺塔问题只能用递归方法求解: 若n==1,直接将圆盘从A柱移到C柱即可,否则 用C柱做为过度,将A柱上的 (n-1)个圆盘移到B柱上 将仍在A柱上的最后一个圆盘直接移到C柱上 用A柱做过度,将B柱上的(n-1)个圆盘移到C柱上
17
返本章 上一页
下一页
含三个圆盘的汉诺塔操作过程示意图:
14
返本章 上一页
下一页
递归过程不同实现方法比较
采用系统提供栈方法(递归算法)的特性:
结构清晰,可读性好。 但要反复地进行程序中断操作,反复进行现场和断点的保 护与恢复,占用资源多,效率很低。 递归算法的裴波那契数列,时间复杂度为O(2n)。 不涉及程序中断操作,不须保护断点,运行效率较递归算 法稍高。 递归算法的裴波那契数列,时间复杂度也为O(2n)。 不涉及栈操作,运行效率最高。 算法结构不如递归算法清晰 递归算法的裴波那契数列,时间复杂度为O(n)。
11
返本章 上一页
下一页
long Fibonacci(long n) //求裴波那契数列函数定义 { Stack<Node> s(50); //用户定义栈 Node* w=new Node; long sum=0; do{ while(n>1) { w->n=n; w->tag=1; s.Push(*w); n- -; } sum+=n; while(! s.IsEmpty()) { *w=s.GetTop(); s.Pop(); if(w->tag==1) { w->tag=2; s.Push(*w); n=w->n-2; break; } } }while(! s.IsEmpty()); return sum; }
C,B为过度柱”,是通过递归实现的
19
返本章 上一页
下一页
含n 个圆盘的汉诺塔递归算法
typedef char String[10]; 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); } } void main() { int n; String startpeg="A",middlepeg="B",endpeg="C"; cout<<"Enter the number of disks :"; cin>>n; cout<<"The solution for n="<<n<<endl; Hanoi(n, startpeg,middlepeg,endpeg); }
fact(2) main() fact(1) fact(2) fact(4) fact(3) fact(3) main() fact(4) fact(1)
fact(2)
fact(3) fact(4) fact(4) fact(1)
fact(3)
main( main( ))
fact(4) 24
4* fact(3) 4*6
用户栈中保存的是不同层递归调用树操作产生的中间结 果数据。 在上层运算即将转入下层运算前,将上层运算的中间结 果入栈。 在下层运算结束退回上层运算时,将上层运算的中间结 果出栈
10
返本章 上一页
下一页
使用用户定义栈求裴波那契数列: (黄色为修改部分) #include<iostream.h> #include "… …\sequence_stack.h" long Fibonacci(long n); //求裴波那契数列函数说明 struct Node //用户栈结点的类定义 { long n; int tag; Node(long m=0,int t=0):n(m),tag(t){ } //构造函数,用于将整型数转换为Node型 }; void main() { long n; cout<<"Enter number :"; cin>>n; for(int i=0;i<=n;i++) cout<<"Fibonacci("<<i<<")="<<Fibonacci(i)<<endl; } (未完,转下页)
⑴ ⑸
⑵
⑹
⑶
⑺
⑷
⑻
18
返本章 上一页
下一页
含n 个圆盘的汉诺塔递归操作过程示意图:
⑴初始状态: ⑵将A盘上面的n-1个盘移到B,C为过度柱
A
B
C
A
B
C
⑶将A盘余下的最大盘移到C
⑷将B盘的n-1个盘移到C,B为过度柱
A
B
C
A
B
C
⑸重复步骤⑴ ~ ⑷,直到n==1止 至于“⑵将A盘上面的n-1个盘移到B,C为过度柱”与“⑷将B盘的n-1个盘移到
若元素Maze[i][j]==1,表示该位置上是障碍 若元素Maze[i][j]==0,表示该位置上是通路