递归算法精品PPT课件
合集下载
PPT-07递推和递归思想
7
① 定 义 数 组 fish[6], 并 初 始 化 为 1; 定 义 循 环 控 制 变 量 i, 并 初 始 化 为 0。
fish[5]=fish[5]+5; // ② .1
②
for ( i=4; i>=1; i-- ) // ② .2
fish[i+1]% 4 != 0
tru e
false
break; //退 出 for 循 环
fa ct(3)
真
3==1
调 用 fa ct(2)
2==1 真
调 用 fa ct(1)
真
1==1
假 假
假
fact(1) =1
返回
fa ct(2)= 2* fa ct(1) 返 回
fa ct(3)= 3* fa ct(2) 返 回
27
在这个图中“内层”与“外层”有着相同的结构。它 们之间“你中有我,我中有你”,呈现相互依存的 关系。
fish[ 4 ] = fish[ 5 ] * 5 / 4 + 1 又要满足
fish[ 4 ] % 5 == 1
显然,fish[ 4 ] 不能不是整数,这个结论同样可以用
至 fish[ 3 ], fish[ 2 ] 和 fish[ 1 ]
6
3 . 按题意要求 5 人合伙捕到的最少鱼数,可以从 小往大枚举,可以先让 E 所看到的鱼数最少为 6 条,即 fish[ 5 ] 初始化为 6 来试,之后每次增加 5 再试,直至递推到 fish[ 1 ] 得整数且除以 5 之后的 余数为 1。 根据上述思路,我们可以构思如下的程序框图:
① 定 义 数 组 fish[6], 并 初 始 化 为 1; 定 义 循 环 控 制 变 量 i, 并 初 始 化 为 0。
fish[5]=fish[5]+5; // ② .1
②
for ( i=4; i>=1; i-- ) // ② .2
fish[i+1]% 4 != 0
tru e
false
break; //退 出 for 循 环
fa ct(3)
真
3==1
调 用 fa ct(2)
2==1 真
调 用 fa ct(1)
真
1==1
假 假
假
fact(1) =1
返回
fa ct(2)= 2* fa ct(1) 返 回
fa ct(3)= 3* fa ct(2) 返 回
27
在这个图中“内层”与“外层”有着相同的结构。它 们之间“你中有我,我中有你”,呈现相互依存的 关系。
fish[ 4 ] = fish[ 5 ] * 5 / 4 + 1 又要满足
fish[ 4 ] % 5 == 1
显然,fish[ 4 ] 不能不是整数,这个结论同样可以用
至 fish[ 3 ], fish[ 2 ] 和 fish[ 1 ]
6
3 . 按题意要求 5 人合伙捕到的最少鱼数,可以从 小往大枚举,可以先让 E 所看到的鱼数最少为 6 条,即 fish[ 5 ] 初始化为 6 来试,之后每次增加 5 再试,直至递推到 fish[ 1 ] 得整数且除以 5 之后的 余数为 1。 根据上述思路,我们可以构思如下的程序框图:
递归算法
递归模型的分解过程不是随意分解,分解问题规模要保
证“大问题”和“小问题”的相似性,即求解过程和环 境要具备相似性;
一旦遇到递归边界,分解过程结束,开始求值,分解是 量变的过程,大问题慢慢变小,但是尚未解决,遇到递
归出口之后,发生了质变,即递归问题转化为直接问题。
因此,递归算法的执行总是分为分解和求值两个部分。
6
递归的定义
什么ห้องสมุดไป่ตู้候使用递归 递归的分类 递归模型的概念
递归的定义
若一个对象部分地包含它自己, 或用它自己给自
己定义, 则称这个对象是递归的;若一个过程直 接地或间接地调用自己, 则称这个过程是递归的 过程。
递归有两种
直接递归:自己调用自己
间接递归:A调用B,B调用A
void tell_story( ) { static int old_monk, young_monk;
old_monk = old_monk + 1; // 年龄大了一岁 young_monk = young_monk + 1; if(old_monk <= 60) // 递归形式 tell_story ( ); else printf("对不起,已退休!"); // 递归边界 }
一般地,一个递归模型是由递归边界和递归体两部分
递归算法课件
求Fib(5)的递归计算过程如图所示。
Fib(5) Fib(4) Fib(3) Fib(2) Fib(1) Fib(2) Fib(3) Fib(2) Fib(1) Fib(0)
Fib(1) Fib(0) Fib(1)
Fib(1) Fib(0)
斐波那契数列Fib(5)的递归调用树
为了计算Fib(5),需要先计算Fib(4)和Fib(3); 而计算Fib(4)又需要计算Fib(3)(再一次计算)和 Fib(2),… … . 由上图可知,为了计算Fib(5),需要计算1次 Fib(4),2次Fib(3),3次Fib(2),5次Fib(1),3次 Fib(0). 加上Fib(5)1次,所有的递归调用次数达到15 次。(图中15个点表示15次运算) 更一般地,设Fib(n)需要总的递归调用次数为 NumCall(n),那么NumCall(n)等于多少?
由此可见,递归算法设计,通常有以 下3个步骤:
• 1. 分析问题,得出递归关系。 • 2. 设置边界条件,控制递归。 • 3. 设计函数,确定参数。
一个典型的例子是在有序数组中查找一个数据元素是否 存在的折半查找算法。 如下例中查找元素17。
第一次: 下标 元素值 0 1 1 3 2 4 3 5 4 17 5 18 6 31 7 33
例2:斐波那契数列为:1、1、2、3、5、8、13、21、…, 即 fib(1)=1; fib(2)=1; fib(n)=fib(n-1)+fib(n-2) (当n>2时)。 我们曾经用迭代法解决了这个问题,实际上数列公式 本身是一个递归公式,如果用递归算法来解将更自然。根据 递归公式,很容易递归函数: int Fib(int n) { if (n < 1) return 0; if (n == 1 || n == 2)// 递归出口 return 1; return Fib(n-1) + Fib(n-2); }
递归算法课件
x[k]:=0 end end ; end. 2 1 0 4 3 1 3 0 4 2 0 3 4 1 2 0 2 1
k
例2、数字排列问题
列出所有从数字1到数字 的连续自然数的排列 列出所有从数字 到数字n的连续自然数的排列 要求所产生的 到数字 的连续自然数的排列,要求所产生的 任一数字序列中不能出现重复的数字. 任一数字序列中不能出现重复的数字. 输入: ( 输入:n(1<=n<=9) ) 输出: 组成的所有不重复的数字序列, 输出:由1~n组成的所有不重复的数字序列,每行一个序列. ~ 组成的所有不重复的数字序列 每行一个序列. 样例 输入: 输入: 3 输出: 输出: 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1
begin readln(n); k:=1; x[k]:=0; while k>0 do begin x[k]:=x[k]+1; while ( x[k]<=n ) and (not place(k)) do x[k]:=x[k]+1; if x[k]>n then( k:=k-1 ) else if( k=n )then print else begin ( k:=k+1 ); x[k]:=0 end end ; end.
年复赛试题) 例3.骑士游历(98年复赛试题 骑士游历 年复赛试题 设有一个n*m的棋盘(2≤n≤17,2≤m≤17),如下图,在棋盘上左下角有 的棋盘( 设有一个 的棋盘 , ) 如下图, 一个中国象棋马。 一个中国象棋马。 (8,4) )
什么是递归算法
这是因为每月的大兔子数目一定等于上月的 兔子总数,而每个月的小兔子数目一定等于上月 的大兔子数目(即前一个月的兔子的数目)。 由上述的递推式我们可以设计出递归程序。 递归程序的特点是独立写出一个函数(或子过程), 而这个函数只对极简单的几种情况直接给出解答, 而在其余情况下通过反复的调用自身而把问题归 结到最简单的情况而得到解答。
(4)调试程序 因为这个算法的效率不高,建议在调试 程序时月份数不要大于40。
知识迁移:
(1)利用递归方法编写一求N的阶乘。 分析: 根据N!=N*(N-1)*(N-2)*(N-3)*……*3*2*1 可以推出下列式子:
Function F(ByVal n As Integer) As Long If n = 1 Then F = 1 Else F = n * F(n - 1) End Function Private Sub Form_Click() Dim n As Integer n = Val(InputBox("请输入正整数N:", "求N 的阶乘")) Print " 输入的正整数是"; n; Print ",阶乘是"; F(n) End Sub
递 归 算 法
什么是递归算法?
递归算法:是一种直接或者间接地调用 自身的算法。在计算机编写程序中,递归 算法对解决一大类问题是十分有效的,它 往往使算法的描述简洁而且易于理解。
C语言与程序设计ppt-第12章递归
2021/4/25
华中科技大学计算机学院C语言课程组
22
分解数组的函数partition
快速排序的核心就是分解步骤,分解数组的函数定义如下。 /* 将数组a中的元素a[left ]至a[right]分成左右两部分,函数返回切分点的下标 */ int partition(int a[ ],int left,int right ) {
int i=left,j=right+1; int split=(left+right)/2; /* 选择数组的中间元素作为切分元素 */
swap(a,left,split);
/* 将切分元素移到数组的开头 */
for ( ; ; )
{
while(a[++i]<=a[left] && i <= right); /*从左至右扫描 */
}
2021/4/25
华中科技大学计算机学院C语言课程组
10
函数Strcmp用递归方式比较指针s和t指向的 两个字符串的大小。函数首先比较两个串的第
一个字符,如果两个字符不同,或它们是空字
符,那么返回递归条件;否则,对两个指针自
增,对函数进行递归调用,继续比较后面的字
符。递归可能在遇到两字符串的第一个不同字 符处终止(两串不同,返回值非0),也可能 在遇到两字符串同为空时终止(两串相同,返 回值0)。
递归及递归算法分析课件
else return n*fact(n-1)
print n;
else p2(n-1);print n;
}
proc p2(n){
if n>0 then
if n mod 3==0 then p1(n-1)
else p2(n-1)
}
8
递归函数举例
例1 阶乘函数 阶乘函数可递归地定义为:
1 n0 n! n(n 1)! n 0
❖ 分治与递归像一对孪生兄弟,经常同时应用 在算法设计之中,并由此产生许多高效算法。
3
2.子程序的内部实现原理
❖ 1)子程序调用的一般形式
一次调用 N次调用 嵌套调用 平行调用
主程序
主程序
主程序
主程序
子程序A
call A 1:
子程序A
call A 1: call A 2:
子程序A 子程序B
call B 2:
些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编 号为1,2,…,n,现要求将塔座a上的这一叠圆盘移到塔座b上, 并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则: 规则1:每次只能移动1个圆盘; 规则2:任何时刻都不允许将较大的圆盘压在较小的圆盘之上; 规则3:在满足移动规则1和2的前提下,可将圆盘移至a,b,c中 任一塔座上。
r2perm(R2)
16
算法设计与分析-递归法
在三根柱子之间一次只能移动一个圆盘。 移动的时候始终只能小圆盘压着大圆盘。 盘子只能在三个柱子上存放。
2、递归算法的思想
假设有n个金盘,三根相邻的柱子标号为A,B,C,并且 A柱上金盘由小到大依次编号为1,2,…,n。现要把按 金字塔状叠放着n个不同大小的圆盘,一个一个移动到柱 子C上。当只有一个盘子时,即n=1,则只需经过一次移 动将盘子从A柱到C柱;当n>1时可以把最上面n-1个金盘 看作是一个整体。这样n个金盘就分成了两部分:上面n-1 个金盘和最下面的1个金盘。移动金盘的问题就转换为以 下步骤来执行: – 借助C柱,将n-1个金盘从A柱上移动到B柱上。 – 将编号为n的金盘直接从A柱移动到C柱上。 – 借助A柱,将n-1个金盘从B柱移动到C柱上。 其中第2步只移动一个金盘,第1步和第3步虽然不能直接 解决,但把移动n个金盘的问题变成了移动n-1个金盘的问 题,使问题的规模变小了。以此类推,从而将整个问题得 以解决。因此汉诺塔问题是一个典型的递归问题。
利用递归算法解决的问题通常具有如下3个特性: (1)求解规模为n的问题可以转化为一个或多个结构相同、规 模较小的问题,然后从这些小问题的解能方便地构造出大问题 的解。 (2)递归调用的次数必须是有限的。 (3)必须有结束递归的条件(边界条件)来终止递归。
举例
求阶乘问题。如果要求n!,那么这个问题就可 以转化成求n*(n-1)!,而要求(n-1)!又可以转化成 求(n-1)* (n-2)!,有规律的递减,直到1!结束。
2、递归算法的思想
假设有n个金盘,三根相邻的柱子标号为A,B,C,并且 A柱上金盘由小到大依次编号为1,2,…,n。现要把按 金字塔状叠放着n个不同大小的圆盘,一个一个移动到柱 子C上。当只有一个盘子时,即n=1,则只需经过一次移 动将盘子从A柱到C柱;当n>1时可以把最上面n-1个金盘 看作是一个整体。这样n个金盘就分成了两部分:上面n-1 个金盘和最下面的1个金盘。移动金盘的问题就转换为以 下步骤来执行: – 借助C柱,将n-1个金盘从A柱上移动到B柱上。 – 将编号为n的金盘直接从A柱移动到C柱上。 – 借助A柱,将n-1个金盘从B柱移动到C柱上。 其中第2步只移动一个金盘,第1步和第3步虽然不能直接 解决,但把移动n个金盘的问题变成了移动n-1个金盘的问 题,使问题的规模变小了。以此类推,从而将整个问题得 以解决。因此汉诺塔问题是一个典型的递归问题。
利用递归算法解决的问题通常具有如下3个特性: (1)求解规模为n的问题可以转化为一个或多个结构相同、规 模较小的问题,然后从这些小问题的解能方便地构造出大问题 的解。 (2)递归调用的次数必须是有限的。 (3)必须有结束递归的条件(边界条件)来终止递归。
举例
求阶乘问题。如果要求n!,那么这个问题就可 以转化成求n*(n-1)!,而要求(n-1)!又可以转化成 求(n-1)* (n-2)!,有规律的递减,直到1!结束。
C语言递归算法PPT演示课件
•6
【例3】Hanoi汉诺塔问题
有N个圆盘,依半径大小(半径都不同),自下而上套在A柱上,每次只允 许移动最上面一个盘子到另外的柱子上去(除A柱外,还有B柱和C柱,开始时这 两个柱子上无盘子),但绝不允许发生柱子上出现大盘子在上,小盘子在下的情 况,现要求设计将A柱子上N个盘子搬移到C柱去的方法。 【算法分析】
•4
【参考程序】
#include<iostream>
#include<cstdlib>
using namespace std;
int a[11];
void search(int,int,int); int main()
//主程序
{
int k,x,L=1,R=10; cout<<"输入10个从大到小顺序的数:"<<endl;
【参考程序】
#include<iostream>
using namespace std;
int ans;
void dfs(int m)
{
int i;
ans++;
for (i = 1; i <= m/2; i++)
dfs(i);
}
int main()
{
int n;
•3
递归及递归算法图解
2、可以利用这个转化过程使问题得到解决。
3、必须有一个明确的结束递归的条件。
递归的概念
15
(3)如何表达延续不断却相似或重复的事物或过程?
数学中的递推式
一个数列的第n项an与该数列的其他一项或多项之间存在某种对应关系,被 表达为一种公式,称为递推式
•第1项(或前K项)的值是已知的— 递推基础; •由第n项或前n项计算第n+1项— 递推规则/递推步骤; •由前向后,可依次计算每一项
运用递归和迭代 (3)运用迭代进行程序构造?
战德臣 教授
运用迭代进行程序构造:具有无限的自相似性步骤的表达,循环替代-递推
n
!
n
(n
1 1)
...
1
当n 1时 当n 1时
(*…(* (* (* (* 1 1) 2) 3) 4) …n)
(define (fact n) (fact-iter 1 1 n))
(fact-iter (* 1 2) (+ 2 1) 6) (fact-iter 2 3 6) (fact-iter (* 2 3) (+ 3 1) 6) (fact-iter 6 4 6) (fact-iter (* 6 4) (+ 4 1) 6) (fact-iter 24 5 6) (fact-iter (* 24 5) (+ 5 1) 6) (fact-iter 120 6 6)
3、必须有一个明确的结束递归的条件。
递归的概念
15
(3)如何表达延续不断却相似或重复的事物或过程?
数学中的递推式
一个数列的第n项an与该数列的其他一项或多项之间存在某种对应关系,被 表达为一种公式,称为递推式
•第1项(或前K项)的值是已知的— 递推基础; •由第n项或前n项计算第n+1项— 递推规则/递推步骤; •由前向后,可依次计算每一项
运用递归和迭代 (3)运用迭代进行程序构造?
战德臣 教授
运用迭代进行程序构造:具有无限的自相似性步骤的表达,循环替代-递推
n
!
n
(n
1 1)
...
1
当n 1时 当n 1时
(*…(* (* (* (* 1 1) 2) 3) 4) …n)
(define (fact n) (fact-iter 1 1 n))
(fact-iter (* 1 2) (+ 2 1) 6) (fact-iter 2 3 6) (fact-iter (* 2 3) (+ 3 1) 6) (fact-iter 6 4 6) (fact-iter (* 6 4) (+ 4 1) 6) (fact-iter 24 5 6) (fact-iter (* 24 5) (+ 5 1) 6) (fact-iter 120 6 6)
第6章 递归
第6章 递归
第6章 章
递 归
6.1 递归的概念 6.2 递归算法的设计 6.3 递归过程和递归工作栈 6.4 递归算法的效率分析 6.5 转化递归算法为非递归算法 6.6 回溯法
第6章 递归
6.1 递归的概念
递归(Recurtion)是一种有效的算法设计方法。 递归的数学定义是:若一个对象部分地包含他自身, 或要用他自身给自己下定义,则称这个对象是递归的 对象。递归算法的定义是:若一个算法直接地或间接 地调用自己,则称这个算法是递归算法。
第6章 递归
本应用例子从另一个角度也可看作是3.3节学过的 顺序堆栈类的应用。我们用3.3节的顺序堆栈类来模拟 系统运行时栈,其数据元素类型Datatype定义如下: struct Datatype { short int retAddr; int nParam; char fromParam; char auxParam; char to Param; }; //模仿返回地址 //参数n //参数fromPeg //参数auxPeg //参数toPeg
2 1 0
1 2 3 n
0 1 2 x (f)
1 * * y
1 * * Fact
(d )
1 0
2 3 n
1 2 x
1 * y
2 * Fact
0
3 n
2 x
2 y
第6章 章
递 归
6.1 递归的概念 6.2 递归算法的设计 6.3 递归过程和递归工作栈 6.4 递归算法的效率分析 6.5 转化递归算法为非递归算法 6.6 回溯法
第6章 递归
6.1 递归的概念
递归(Recurtion)是一种有效的算法设计方法。 递归的数学定义是:若一个对象部分地包含他自身, 或要用他自身给自己下定义,则称这个对象是递归的 对象。递归算法的定义是:若一个算法直接地或间接 地调用自己,则称这个算法是递归算法。
第6章 递归
本应用例子从另一个角度也可看作是3.3节学过的 顺序堆栈类的应用。我们用3.3节的顺序堆栈类来模拟 系统运行时栈,其数据元素类型Datatype定义如下: struct Datatype { short int retAddr; int nParam; char fromParam; char auxParam; char to Param; }; //模仿返回地址 //参数n //参数fromPeg //参数auxPeg //参数toPeg
2 1 0
1 2 3 n
0 1 2 x (f)
1 * * y
1 * * Fact
(d )
1 0
2 3 n
1 2 x
1 * y
2 * Fact
0
3 n
2 x
2 y
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第二章 递归算法
主要内容
➢ 1、递归的概念 ➢ 2、递归算法的设计方法 ➢ 3、递归算法的执行过程 ➢ 4、递归算法的效率分析
递归概念的引入
一个小故事: 山上有座庙,庙里有个老和尚,老和尚在
讲故事,它讲的故事是:山上有座庙,庙 里有个老和尚,老和尚在讲故事,它讲的 故事是:…… 小故事的特点?
由经典故事到程序设计
就象上面的故事那样,故事中包含了故事本身——自己调用自己。 程序设计中函数的出现——因为对自身进行调用,所以需对程序段进
行包装,也就出现了函数。 函数的利用是对数学上函数定义的推广,函数的正确运用有利于简化
程序,也能使某些问题得到迅速实现。对于代码中功能性较强的、重 复执行的或经常要用到的部分,将其功能加以集成,通过一个名称和 相应的参数来完成,这就是函数或子程序,使用时只需对其名字进行 简单调用就能来完成特定功能。 例如我们把上面的讲故事的过程包装成一个函数,就会得到:
基本思路: - 将目标值与数组的中间元素进行比较; - 若相等,查找成功。否则根据比较的结果 将查找范围缩小一半,然后重复此过程。
请问: 是否在 此列表当中?
14
请问: 是否在 此列表当中?
数组正 中间的 元素。
15
请问: 是否在 此列表当中?
不予考虑
16
请问: 是否在 此列表当中?
正中间 的元素
17
请问: 是否在 此列表当中?
?
不予考虑
正中间 的元素
18
void main() {
int b[] = {05, 13, 19, 21, 37, 56, 64, 75, 80, 88, 92};
int x = 21;
printf("x位于数组的第%d个元素\n", bsearch(b, x, 0, 10));
经典故事的程序设计
void Story()
{
运
puts("从前有座山,山里有座庙,庙里有个老和尚,老和尚在讲故 事,它讲的故事是:");
getchar();//按任意键听下一个故事的内容
行 程
Story(); //老和尚讲的故事,实际上就是上面那个故事
序
}
函数的功能? ——输出这个故事的内容,等用户按任意键后,重复的输出这段
f(n)=
n*f(n-1)
当n>0时
第一种递归
也就是说,函数f(n)的定义用到了自己本身f(n-1)
什么时候使用递归
2. 数据结构是递归的
有些数据结构是递归的。例如,第2章中介绍过的单链表 就是一种递归数据结构,其结点类型定义如下:
typedef struct LNode
{
ElemType data;
old_monk = old_monk + 1; // 年龄大了一岁
young_monk = young_monk + 1;
if(old_monk <= 60)
// 递归形式
tell_story ( );
else
printf("对不起,已退休!"); // 递归边界
}
6
1、递归的概念
递归的定义 什么时候使用递归 递归的分类 递归模型的概念
内容。我们发现由于每个故事都是相同的,所以出现导致死循 环的迂回逻辑,故事将不停的讲下去。 出现死循环的程序是一个不健全的程序,我们希望程序在满足某 种条件以后能够停下来,正如我们听了几遍相同的故事后会大 叫:“够了!”。 于是我们可以得到下面的程序:
void tell_story( ) {
static int old_monk, young_monk;
int Sum(LinkList *head)
{
if (head==NULL)
Байду номын сангаас
return 0;
else
return(head->data+Sum(head->next));
}
什么时候使用递归
3. 问题的求解方法是递归的
一个典型的例子是在有序数组中查找一个数据元素是否存 在的折半查找算法
前提:数据是有序排列的;
1、递归的概念
递归的定义
▪ 若一个对象部分地包含它自己, 或用它自己给自 己定义, 则称这个对象是递归的;若一个过程直 接地或间接地调用自己, 则称这个过程是递归的 过程。
递归有两种
▪ 直接递归:自己调用自己 ▪ 间接递归:A调用B,B调用A
2、什么时候使用递归?
1. 问题的定义是递归的
有许多数学公式、数列等的定义是递归的。例如,求n!
}
如何用递归来实现?
19
问题分析
1. 函数原型: int bsearch(int b[], int x, int L, int R);
2. 递归的形式? 3. 递归的边界?
20
int bsearch(int b[], int x, int L, int R) {
int mid;
if(L > R) return(-1); mid = (L + R)/2; if(x == b[mid])
和Fibonacci数列等。这些问题的求解过程可以将其递归
定义直接转化为对应的递归算法。
例如:阶乘函数的定义
1
当n=0时
n!=
n*(n-1)*…*1 当n>0时
什么时候使用递归
阶乘的另外一种定义方法
1
n!=
n*(n-1) !
当n=0时 当n>0时
这时候递归的定义可以用如下的函数表示:
1
当n=0时
return mid; else if(x < b[mid])
return bsearch(b, x, L, mid-1); else
return bsearch(b, x, mid+1, R); }
21
什么时候使用递归
折半查找中的递归现象总结
折半查找无非就是三种情况,其中两种情况的问 题解法如果以算法来表示,都存在算法调用自身 的情况。 递归算法的特点就是:将问题分解成为形式上更 加简单的子问题来进行求解。递归算法不但是一 种有效的分析问题方法,也是一种有效的算法设 计方法,是解决很多复杂问题的重要方法。
第二种递归
struct LNode *next;
} LinkList;
该定义中,结构体LNode的定义中用到了它自身,即指 针域next是一种指向自身类型的指针,所以它是一种递 归数据结构。
什么时候使用递归
对于递归数据结构,采用递归的方法编写算法既方便 又有效。例如,求一个不带头结点的单链表head的 所有data域(假设为int型)之和的递归算法如下:
主要内容
➢ 1、递归的概念 ➢ 2、递归算法的设计方法 ➢ 3、递归算法的执行过程 ➢ 4、递归算法的效率分析
递归概念的引入
一个小故事: 山上有座庙,庙里有个老和尚,老和尚在
讲故事,它讲的故事是:山上有座庙,庙 里有个老和尚,老和尚在讲故事,它讲的 故事是:…… 小故事的特点?
由经典故事到程序设计
就象上面的故事那样,故事中包含了故事本身——自己调用自己。 程序设计中函数的出现——因为对自身进行调用,所以需对程序段进
行包装,也就出现了函数。 函数的利用是对数学上函数定义的推广,函数的正确运用有利于简化
程序,也能使某些问题得到迅速实现。对于代码中功能性较强的、重 复执行的或经常要用到的部分,将其功能加以集成,通过一个名称和 相应的参数来完成,这就是函数或子程序,使用时只需对其名字进行 简单调用就能来完成特定功能。 例如我们把上面的讲故事的过程包装成一个函数,就会得到:
基本思路: - 将目标值与数组的中间元素进行比较; - 若相等,查找成功。否则根据比较的结果 将查找范围缩小一半,然后重复此过程。
请问: 是否在 此列表当中?
14
请问: 是否在 此列表当中?
数组正 中间的 元素。
15
请问: 是否在 此列表当中?
不予考虑
16
请问: 是否在 此列表当中?
正中间 的元素
17
请问: 是否在 此列表当中?
?
不予考虑
正中间 的元素
18
void main() {
int b[] = {05, 13, 19, 21, 37, 56, 64, 75, 80, 88, 92};
int x = 21;
printf("x位于数组的第%d个元素\n", bsearch(b, x, 0, 10));
经典故事的程序设计
void Story()
{
运
puts("从前有座山,山里有座庙,庙里有个老和尚,老和尚在讲故 事,它讲的故事是:");
getchar();//按任意键听下一个故事的内容
行 程
Story(); //老和尚讲的故事,实际上就是上面那个故事
序
}
函数的功能? ——输出这个故事的内容,等用户按任意键后,重复的输出这段
f(n)=
n*f(n-1)
当n>0时
第一种递归
也就是说,函数f(n)的定义用到了自己本身f(n-1)
什么时候使用递归
2. 数据结构是递归的
有些数据结构是递归的。例如,第2章中介绍过的单链表 就是一种递归数据结构,其结点类型定义如下:
typedef struct LNode
{
ElemType data;
old_monk = old_monk + 1; // 年龄大了一岁
young_monk = young_monk + 1;
if(old_monk <= 60)
// 递归形式
tell_story ( );
else
printf("对不起,已退休!"); // 递归边界
}
6
1、递归的概念
递归的定义 什么时候使用递归 递归的分类 递归模型的概念
内容。我们发现由于每个故事都是相同的,所以出现导致死循 环的迂回逻辑,故事将不停的讲下去。 出现死循环的程序是一个不健全的程序,我们希望程序在满足某 种条件以后能够停下来,正如我们听了几遍相同的故事后会大 叫:“够了!”。 于是我们可以得到下面的程序:
void tell_story( ) {
static int old_monk, young_monk;
int Sum(LinkList *head)
{
if (head==NULL)
Байду номын сангаас
return 0;
else
return(head->data+Sum(head->next));
}
什么时候使用递归
3. 问题的求解方法是递归的
一个典型的例子是在有序数组中查找一个数据元素是否存 在的折半查找算法
前提:数据是有序排列的;
1、递归的概念
递归的定义
▪ 若一个对象部分地包含它自己, 或用它自己给自 己定义, 则称这个对象是递归的;若一个过程直 接地或间接地调用自己, 则称这个过程是递归的 过程。
递归有两种
▪ 直接递归:自己调用自己 ▪ 间接递归:A调用B,B调用A
2、什么时候使用递归?
1. 问题的定义是递归的
有许多数学公式、数列等的定义是递归的。例如,求n!
}
如何用递归来实现?
19
问题分析
1. 函数原型: int bsearch(int b[], int x, int L, int R);
2. 递归的形式? 3. 递归的边界?
20
int bsearch(int b[], int x, int L, int R) {
int mid;
if(L > R) return(-1); mid = (L + R)/2; if(x == b[mid])
和Fibonacci数列等。这些问题的求解过程可以将其递归
定义直接转化为对应的递归算法。
例如:阶乘函数的定义
1
当n=0时
n!=
n*(n-1)*…*1 当n>0时
什么时候使用递归
阶乘的另外一种定义方法
1
n!=
n*(n-1) !
当n=0时 当n>0时
这时候递归的定义可以用如下的函数表示:
1
当n=0时
return mid; else if(x < b[mid])
return bsearch(b, x, L, mid-1); else
return bsearch(b, x, mid+1, R); }
21
什么时候使用递归
折半查找中的递归现象总结
折半查找无非就是三种情况,其中两种情况的问 题解法如果以算法来表示,都存在算法调用自身 的情况。 递归算法的特点就是:将问题分解成为形式上更 加简单的子问题来进行求解。递归算法不但是一 种有效的分析问题方法,也是一种有效的算法设 计方法,是解决很多复杂问题的重要方法。
第二种递归
struct LNode *next;
} LinkList;
该定义中,结构体LNode的定义中用到了它自身,即指 针域next是一种指向自身类型的指针,所以它是一种递 归数据结构。
什么时候使用递归
对于递归数据结构,采用递归的方法编写算法既方便 又有效。例如,求一个不带头结点的单链表head的 所有data域(假设为int型)之和的递归算法如下: