1、计算机程序设计基础计算机程序设计基础第六讲第六讲 递归递归1递归算法递归算法在可计算性理论中占有重要地位,它是算法设在可计算性理论中占有重要地位,它是算法设计的有力工具,对于拓展编程思路非常有用。就递归计的有力工具,对于拓展编程思路非常有用。就递归算法而言并不涉及高深数学知识,只不过初学者要建算法而言并不涉及高深数学知识,只不过初学者要建立起递归概念不十分容易。立起递归概念不十分容易。我们先从一个最简单的例子导入。我们先从一个最简单的例子导入。递归及其实现递归及其实现用递归算法求用递归算法求n!定义:函数定义:函数 fact(n)=n!fact(n-1)=(n-1)!则有则有 fact(n)=
2、n fact(n-1)已知已知 fact(1)=12为了表述得直观清晰,我们定义两个结点:为了表述得直观清晰,我们定义两个结点:或结点或结点与与与与结点。结点。图示的直观性与思维助力。图示的直观性与思维助力。1、或结点、或结点A为为“或结点或结点”,A依不同条件会有两种不同的取值依不同条件会有两种不同的取值B或或C。结点用。结点用 表示。表示。3如果有多于如果有多于2种取值,可用下图:种取值,可用下图:条件为条件为Z1,Z2,Z1,Z2,Zn,Zn,取值为,取值为B B或或C,C,或或G G42、与结点、与结点与结点要涂黑,相关联与结点要涂黑,相关联的的B B与与C C之间要用弧线之间要用弧线
3、连起来。连起来。A A为与结点,为与结点,A A的最终取值为的最终取值为C C结点的值,但为了结点的值,但为了求得求得C C的值,得先求出的值,得先求出B B结点的值,结点的值,C C是是B B的函数。的函数。5仍以求仍以求n!为例画出如下与或图为例画出如下与或图A为或结点;为或结点;B为直接可解结点,值为为直接可解结点,值为1;C为与结点,当为与结点,当n1时,时,A的取值即的取值即C的值,而的值,而C的值即的值即E的值,为了求得的值,为了求得E的值,需要先求出的值,需要先求出D的值。的值。D值值fact(n-1)乘以乘以n即为即为E的值。的值。6与结点可能有多个相关联的点,这时可描述为下图
4、与结点可能有多个相关联的点,这时可描述为下图A结点的值最终为结点的值最终为D的值,但为了求的值,但为了求D需先求需先求B和和C。从。从图上看先求左边的点才能求最右边的点的值,我们约图上看先求左边的点才能求最右边的点的值,我们约定最右边定最右边D点的值就是点的值就是A结点的值。结点的值。7下面我们以下面我们以3!为例来画与或结点图,目的是体会递归!为例来画与或结点图,目的是体会递归的含义。的含义。C=1D=2*C=2B=D=2E=3*B=3*2=6A=E=68下面画出了调用和返回的递归示意图下面画出了调用和返回的递归示意图9从图可以想象:从图可以想象:欲求欲求fact(3),先要求,先要求fac
5、t(2);要求;要求fact(2)先求先求fact(1)。就象剥一颗圆白菜,从外向里,一层层剥下来,到了就象剥一颗圆白菜,从外向里,一层层剥下来,到了菜心,遇到菜心,遇到1的阶乘,其值为的阶乘,其值为1,到达了递归的边界。,到达了递归的边界。然后再用然后再用fact(n)=n*fact(n-1)这个普遍公式,从里向这个普遍公式,从里向外倒推回去得到外倒推回去得到fact(n)的值。的值。为了把这个问题说得再透彻一点。我们画了如下的流程为了把这个问题说得再透彻一点。我们画了如下的流程图:图:1011为了形象地描述递归过程,将上图改画成下图为了形象地描述递归过程,将上图改画成下图12在这个图中在这
6、个图中“内层内层”与与“外层外层”有着相同的结构。它们有着相同的结构。它们之间之间“你中有我,我中有你你中有我,我中有你”,呈现相互依存的关系。,呈现相互依存的关系。为了进一步讲清递归的概念,将为了进一步讲清递归的概念,将递归递归与与递推递推做一比较。做一比较。仍以求阶乘为例。仍以求阶乘为例。递推递推是从已知的初始条件出发,逐次去求所需要的阶乘是从已知的初始条件出发,逐次去求所需要的阶乘值。值。如求如求3!初始条件初始条件 fact(1)=1fact(2)=2*fact(1)=2fact(3)=3*fact(2)=613这相当于从菜心这相当于从菜心“推到推到”外层。而外层。而递归递归算法的出发
7、点不算法的出发点不放在初始条件上,而放在求解的目标上,从所求的未放在初始条件上,而放在求解的目标上,从所求的未知项出发逐次调用本身的求解过程,直到递归的边界知项出发逐次调用本身的求解过程,直到递归的边界(即初始条件)。就本例而言,读者会认为递归算法(即初始条件)。就本例而言,读者会认为递归算法可能是多余的,费力而不讨好。可能是多余的,费力而不讨好。但许多实际问题不可但许多实际问题不可能或不容易找到显而易见的递推关系,这时递归算法能或不容易找到显而易见的递推关系,这时递归算法就表现出了明显的优越性。就表现出了明显的优越性。下面我们将会看到,递归下面我们将会看到,递归算法比较符合人的思维方式,逻辑
8、性强,可将问题描算法比较符合人的思维方式,逻辑性强,可将问题描述得简单扼要,具有良好的可读性,易于理解,许多述得简单扼要,具有良好的可读性,易于理解,许多看来相当复杂,或难以下手的问题,如果能够使用递看来相当复杂,或难以下手的问题,如果能够使用递归算法就会使问题变得易于处理。下面举一个尽人皆归算法就会使问题变得易于处理。下面举一个尽人皆知的例子知的例子哈诺(哈诺(Hanoi)塔)塔问题。问题。14故事:相传在古代印度的故事:相传在古代印度的Bramah庙中,有位僧子整天庙中,有位僧子整天把三根柱子上的金盘倒来倒去,原来他是想把把三根柱子上的金盘倒来倒去,原来他是想把64个一个一个比一个小的金盘
9、从一根柱子上移到另一根柱子上去。个比一个小的金盘从一根柱子上移到另一根柱子上去。移动过程中恪守下述规则:每次只允许移动一只盘,移动过程中恪守下述规则:每次只允许移动一只盘,且大盘不得落在小盘上面。有人会觉得这很简单,真且大盘不得落在小盘上面。有人会觉得这很简单,真的动手移盘就会发现,如以每秒移动一只盘子的话,的动手移盘就会发现,如以每秒移动一只盘子的话,按照上述规则将按照上述规则将64只盘子从一个柱子移至另一个柱子只盘子从一个柱子移至另一个柱子上,所需时间约为上,所需时间约为5800亿年。亿年。15怎样编写这种程序?从思路上还是先从最简单的情况分怎样编写这种程序?从思路上还是先从最简单的情况分
10、析起,搬一搬看,慢慢理出思路。析起,搬一搬看,慢慢理出思路。1、在、在A柱上只有一只盘子,假定盘号为柱上只有一只盘子,假定盘号为1,这时只,这时只需将该盘从需将该盘从A搬至搬至C,一次完成,记为,一次完成,记为move 1 from A to C162、在、在A柱上有二只盘子,柱上有二只盘子,1为小盘,为小盘,2为大盘。为大盘。第(第(1)步将)步将1号盘从号盘从A移至移至B,这是为了让,这是为了让2号盘能移动;号盘能移动;第(第(2)步将)步将2号盘从号盘从A移至移至C;第(第(3)步再将)步再将1号盘从号盘从B移至移至C;这三步记为:这三步记为:move 1 from A to B;mov
11、e 2 from A to C;move 3 form B to C;173 3、在、在A A柱上有柱上有3 3只盘子,从小到大分别为只盘子,从小到大分别为1 1号,号,2 2号,号,3 3号号第(第(1 1)步将)步将1 1号盘和号盘和2 2号盘视为一个整体;先将二者作为号盘视为一个整体;先将二者作为整体从整体从A A移至移至B B,给,给3 3号盘创造能够一次移至号盘创造能够一次移至C C的机会。这的机会。这一步记为一步记为move(2,A,C,B)意思是将上面的意思是将上面的2 2只盘子作为整体从只盘子作为整体从A A借助借助C C移至移至B B。第(第(2 2)步将)步将3 3号盘从号
12、盘从A A移至移至C C,一次到位。记为,一次到位。记为move 3 from A to C第(第(3 3)步处于)步处于B B上的作为一个整体的上的作为一个整体的2 2只盘子,再移至只盘子,再移至C C。这一步记为这一步记为move(2,B,A,C)意思是将意思是将2 2只盘子作为整体从只盘子作为整体从B B借助借助A A移至移至C C。所谓所谓借助借助是什么意思,等这件事做完了不言自明。是什么意思,等这件事做完了不言自明。18194、从题目的约束条件看,大盘上可以随便摞小盘,相、从题目的约束条件看,大盘上可以随便摞小盘,相反则不允许。在将反则不允许。在将1号和号和2号盘当整体从号盘当整体从
13、A移至移至B的过的过程中程中move(2,A,C,B)实际上是分解为以下三步实际上是分解为以下三步第(第(1).1步:步:move 1 form A to C;第(第(1).2步:步:move 2 form A to B;第(第(1).3步:步:move 1 form C to B;经过以上步骤,将经过以上步骤,将1号和号和2号盘作为整体从号盘作为整体从A移至移至B,为,为3号盘从号盘从A移至移至C创造了条件。同样,创造了条件。同样,3号盘一旦到了号盘一旦到了C,就要考虑如何实现将,就要考虑如何实现将1号和号和2号盘当整体从号盘当整体从B移至移至C的过程了。实际上的过程了。实际上move(2,
14、B,A,C)也要分解为三步:也要分解为三步:第(第(3).1步:步:move 1 form B to A;第(第(3).2步:步:move 2 form B to C;第(第(3).3步:步:move 1 form A to C;205、看、看move(2,A,C,B)是说要将是说要将2只盼自从只盼自从A搬至搬至B,但,但没有没有C是不行的,因为第(是不行的,因为第(1).1步就要将步就要将1盘从盘从A移移到到C,给,给2盘创造条件从盘创造条件从A移至移至B,然后再把,然后再把1盘从盘从C移移至至B。看到这里就能明白借助。看到这里就能明白借助C的含义了。因此,在的含义了。因此,在构思搬移过程的
15、参量时,要把构思搬移过程的参量时,要把3个柱子都用上。个柱子都用上。6、定义搬移函数、定义搬移函数move(n,A,B,C),物理意义是将,物理意义是将n只只盘子从盘子从A经经B搬到搬到C考虑到前面已经考虑到前面已经研究过的研究过的(1)(2)(3)步,可步,可以将搬移过程以将搬移过程用如下的与或用如下的与或结点图表示。结点图表示。21这里用与或结点的含义是分解为这里用与或结点的含义是分解为(1)(2)(3)步。这步。这3步是步是相关的,相互依存的,而且是有序的,从左至右执行。相关的,相互依存的,而且是有序的,从左至右执行。move(n,A,B,C)分解为分解为3步步(1)move(n-1,A
16、,C,B)理解为将上面的理解为将上面的n-1只盘子作为一只盘子作为一个整体从个整体从A经经C移至移至B;(2)输出输出n:A to C,理解将,理解将n号盘从号盘从A移至移至C,是直接可,是直接可解结点;解结点;(3)Move(n-1,B,A,C)理解为将上面的理解为将上面的n-1只盘子作为一只盘子作为一个整体从个整体从B经经A移至移至C。22这里显然是一种递归定义,当着解这里显然是一种递归定义,当着解move(n-1,A,C,B)时时又可想到,将其分解为又可想到,将其分解为3步:步:第第1步:将上面的步:将上面的n-2只盘子作为一个整体从只盘子作为一个整体从A经经B到到C,move(n-2,A,B,C);第第2步:第步:第n-1号盘子从号盘子从A直接移至直接移至B,即,即n-1:A to B;第第3步:再将上面的步:再将上面的n-2只盘子作为一个整体从只盘子作为一个整体从C经经A移移至至B,move(n-2,C,A,B);下面,我们还是以下面,我们还是以3只盘子为例画出递归的与或图。只盘子为例画出递归的与或图。23这个图很象一颗倒置着的树,结点这个图很象一颗倒置着的树,结点move(
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1