`

递归算法

阅读更多
.


原文:http://leihong511.blog.163.com/blog/static/47256469200962353527696/


递归算法的定义:如果一个对象的描述中包含它本身,我们就称这个对象是递归的,这种用递归来描述的算法称为递归算法。

我们先来看看大家熟知的一个的故事:

从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事,他说从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事,他说……

上面的故事本身是递归的,用递归算法描述:

procedure bonze-tell-story;

begin

  if 讲话被打断 then 故事结束

  else begin

从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事;

bonze-tell-story;

end

end;

从上面的递归事例不难看出,递归算法存在的两个必要条件:

(1)    必须有递归的终止条件;

(2)    过程的描述中包含它本身;

在设计递归算法中,如何将一个问题转化为递归的问题,是初学者面临的难题,下面我们通过分析汉诺塔问题,看看如何用递归算法来求解问题;

例1:汉诺塔问题,如下图,有A、B、C三根柱子。A柱子上按从小到大的顺序堆放了N个盘子,现在要把全部盘子从A柱移动到C柱,移动过程中可以借助B柱。移动时有如下要求:

(1)    一次只能移动一个盘子;

(2)    不允许把大盘放在小盘上边;

(3)    盘子只能放在三根柱子上;

算法分析:当盘子比较多的时,问题比较复杂,所以我们先分析简单的情况:

如果只有一个盘子,只需一步,直接把它从A柱移动到C柱;

如果是二个盘子,共需要移动3步:

(1)    把A柱上的小盘子移动到B柱;

(2)    把A柱上的大盘子移动到C柱;

(3)    把B柱上的大盘子移动到C柱;

如果N比较大时,需要很多步才能完成,我们先考虑是否能把复杂的移动过程转化为简单的移动过程,如果要把A柱上最大的盘子移动到C柱上去,必须先把上面的N-1个盘子从A柱移动到B柱上暂存,按这种思路,就可以把N个盘子的移动过程分作3大步:

(1)    把A柱上面的N-1个盘子移动到B柱;

(2)    把A柱上剩下的一个盘子移动到C柱;

(3)    把B柱上面的N-1个盘子移动到C柱;

其中N-1个盘子的移动过程又可按同样的方法分为三大步,这样就把移动过程转化为一个递归的过程,直到最后只剩下一个盘子,按照移动一个盘子的方法移动,递归结束。

递归过程:

procedure Hanoi(N,A,B,C:integer;);{以B柱为中转柱将N个盘子从A柱移动到C柱}

begin

  if N=1 then write(A,’->’,C){把盘子直接从A移动到C}

else begin

  Hanoi(N-1,A,C,B);{ 以C柱为中转柱将N-1个盘子从A柱移动到B柱}

  write(A,’->’,C);{把剩下的一个盘子从A移动到C}

  Hanoi(N-1,B,A,C); { 以A柱为中转柱将N-1个盘子从B柱移动到C柱}

end;

end;

从上面的例子我们可以看出,在使用递归算法时,首先弄清楚简单情况下的解法,然后弄清楚如何把复杂情况归纳为更简单的情况。

在信息学奥赛中有的问题的结构或所处理的数据本身是递归定义的,这样的问题非常适合用递归算法来求解,对于这类问题,我们把它分解为具有相同性质的若干个子问题,如果子问题解决了,原问题也就解决了。

例2求先序排列 (NOIP2001pj)

[问题描述]给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度≤8)。

[样例] 输入:BADC BDCA   输出:ABCD

算法分析:我们先看看三种遍历的定义:

先序遍历是先访问根结点,再遍历左子树,最后遍历右子树;

中序遍历是先遍历左子树,再访问根结点,最后遍历右子树;

后序遍历是先遍历左子树,再遍历右子树,最后访问根结点;

从遍历的定义可知,后序排列的最后一个字符即为这棵树的根节点;在中序排列中,根结点前面的为其左子树,根结点后面的为其右子树;我们可以由后序排列求得根结点,再由根结点在中序排列的位置确定左子树和右子树,把左子树和右子树各看作一个单独的树。这样,就把一棵树分解为具有相同性质的二棵子树,一直递归下去,当分解的子树为空时,递归结束,在递归过程中,按先序遍历的规则输出求得的各个根结点,输出的结果即为原问题的解。

源程序

program noip2001_3;

var z,h : string;

procedure make(z,h:string); {z为中序排列,h为后序排列}

var s,m : integer;

begin

  m:=length(h);{m为树的长度}

 write(h[m]); {输出根节点}

 s:=pos(h[m],z); {求根节点在中序排列中的位置}

 if s>1 then make(copy(z,1,s-1),copy(h,1,s-1)); {处理左子树}

 if m>s then make(copy(z,s+1,m-s),copy(h,s,m-s)); {处理右子树}

end;

begin

 readln(z);

 readln(h);

 make(z,h);

end.

递归算法不仅仅是用于求解递归描述的问题,在其它很多问题中也可以用到递归思想,如回溯法、分治法、动态规划法等算法中都可以使用递归思想来实现,从而使编写的程序更加简洁。

比如上期回溯法所讲的例2《数的划分问题》,若用递归来求解,程序非常短小且效率很高,源程序如下

var

  n,k:integer;

  tol:longint;

procedure make(sum,t,d:integer);

var i:integer;

begin

  if d=k then inc(tol)

  else for i:=t to sum div 2 do make(sum-i,i,d+1);

end;

begin

  readln(n,k);

tol:=0;

  make(n,1,1);

  writeln(tol);

end.

 

有些问题本身是递归定义的,但它并不适合用递归算法来求解,如斐波那契(Fibonacci)数列,它的递归定义为:

F(n)=1          (n=1,2)

F(n)=F(n-2)+F(n-1) (n>2)

用递归过程描述为:

Funtion fb(n:integer):integer;

Begin

  if n<3 then fb:=1 

else fb:=fb(n-1)+fb(n-2);

End;

上面的递归过程,调用一次产生二个新的调用,递归次数呈指数增长,时间复杂度为O(2n),把它改为非递归:

x:=1;y:=1;

for i:=3 to n do

begin

  z:=y;y:=x+y;x:=z;

end;

修改后的程序,它的时间复杂度为O(n)。

我们在编写程序时是否使用递归算法,关键是看问题是否适合用递归算法来求解。由于递归算法编写的程序逻辑性强,结构清晰,正确性易于证明,程序调试也十分方便,在NOIP中,数据的规模一般也不大,只要问题适合用递归算法求解,我们还是可以大胆地使用递归算法。


.

分享到:
评论

相关推荐

    VC对磁盘文件遍历搜索的递归算法和非递归算法

    在VC++(Visual C++)环境中,有多种方法可以实现这一目标,其中最常见的是递归算法和非递归算法。这两种方法各有优缺点,适用于不同的场景。 **递归算法**: 递归算法是一种基于函数自身调用解决问题的方法。在...

    5!递归算法和非递归算法

    递归算法和非递归算法 在计算机科学与编程领域中,递归算法与非递归算法是两种非常重要的计算方法。本文将详细介绍这两种算法的特点、应用场景以及如何实现它们,特别针对初学者及面试准备者。 #### 递归算法 ...

    acm递归算法总结竞赛

    在ACM(国际大学生程序设计竞赛)中,递归算法是一种常见的解决问题的方法,它通过函数自身调用自身来实现问题的解决。递归的核心在于找到基本情况(base case),即可以直接求解的问题,以及每次递归调用时问题规模...

    汉诺塔问题的非递归算法

    对于解决汉诺塔问题,传统方法是通过递归算法实现,即通过不断将问题规模缩小,直到简化到最基本的情况,然后逐步返回并解决每一层的子问题。然而,递归算法在处理大量圆盘时容易引起调用栈过深,导致效率低下。因此...

    .net 递归算法 .net 递归算法.net 递归算法

    在.NET编程环境中,递归算法是一种强大的工具,它允许函数或方法调用自身来解决复杂问题。递归的核心思想是将大问题分解为相同或相似的小问题,直到问题变得足够简单,可以直接得出答案。这种解决问题的方式在数据...

    abap简单递归算法

    ### ABAP简单递归算法解析 #### 一、引言 ABAP(Advanced Business Application Programming)是一种用于SAP系统的编程语言。它不仅支持传统的过程化编程,还支持面向对象编程和Web开发。本文将深入探讨一个ABAP中...

    递归算法与循环算法的分析

    递归算法与循环算法的分析 递归算法是指在程序设计中,在调用一个函数的过程中又出现直接或间接调用其函数本身的现象。递归算法的优点是编写容易,结构清晰,可读性强,但是其缺点是计算速度慢,时间花费较长,效率...

    Hanoi塔问题的一种非递归算法

    ### Hanoi塔问题的一种非递归算法:深入解析与实现 #### 一、引言 Hanoi塔问题作为计算机科学领域内经典的递归问题之一,因其简洁性和挑战性而广受关注。通常,Hanoi塔问题的解决方案多采用递归算法,尽管其逻辑...

    递归算法ppt让你快速上手

    "递归算法ppt让你快速上手" 递归算法是计算机科学中的一种重要算法思想,它可以解决许多复杂的问题。下面是递归算法的知识点总结: 1. 递归的定义:若一个对象部分地包含它自己,或用它自己给自己定义,则称这个...

    合并排序递归和非递归算法

    3. **可读性和实现难度**:递归算法通常代码简洁,易于理解,而非递归算法可能需要更复杂的逻辑来模拟递归行为。 总的来说,选择哪种实现方式取决于具体场景,如内存限制、性能要求以及代码的可读性等。递归版本的...

    中序遍历二叉树非递归算法

    在IT领域,尤其是在数据结构与算法的学习中,中序遍历二叉树的非递归算法是一个关键且实用的知识点。通常,我们首先通过递归来实现二叉树的遍历,但递归方法可能因深度过大导致栈溢出,因此掌握非递归版本的遍历算法...

    程序设计中递归算法

    ### 递归算法在程序设计中的应用 #### 一、递归的概念与本质 递归是一种重要的编程思想,在计算机科学和数学领域都有广泛的应用。它指的是一个过程或函数直接或间接地调用自身来解决问题的方法。递归的核心在于将...

    快速排序算法设计与分析总结 二叉树与树的转换前序、后序的递归、非递归算法,层次序的非递归算法的实现

    快速排序算法设计与分析总结 二叉树与树的转换前序、后序的递归、非递归算法,层次序的非递归算法的实现 二叉树与树的转换前序、后序的递归、非递归算法,层次序的非递归算法的实现,应包含建树的实现 实现树与...

    折半查找的递归算法

    ### 折半查找的递归算法 #### 一、引言 折半查找(也称为二分查找)是一种高效的查找算法,适用于有序数组。通过不断将查找区间对半分割,可以快速定位目标值的位置,时间复杂度为O(log n),其中n是数组长度。本文...

    递归算法专题ppt

    ### 递归算法专题知识点详解 #### 一、递归算法原理 递归算法是一种将问题分解成子问题的方法,其中子问题与原问题性质相同但规模较小。递归算法的关键在于识别出能够通过递归解决的问题,并找到递归的基本情况...

    利用递归算法求阶乘(VB6.0源代码)利用递归算法求阶乘

    在这个主题中,我们将深入探讨如何使用递归算法在VB6.0(Visual Basic 6.0)中计算阶乘。VB6.0是Microsoft开发的一款经典可视化编程环境,用于创建Windows应用程序。 阶乘是一个数学概念,表示一个正整数n的所有...

    递归算法的详解,各种常见递归算法

    递归算法是一种强大的编程技术,它通过函数或过程在解决问题时调用自身来解决更小规模的相同问题。递归的基本概念在于一个函数在定义中包含对自身的引用,或者问题的解决方案依赖于较小规模问题的解决方案。在程序...

    阿克曼函数 c程序 递归与非递归算法的综合

    在这个压缩包中,你将找到两个关于阿克曼函数的C语言实现:一个使用了递归算法,另一个则通过栈来模拟递归。 首先,让我们深入理解阿克曼函数。它通常定义为A(m, n),其中m和n是正整数。阿克曼函数的计算规则如下:...

    程序2_delphi_milemut_递归算法_

    在编程领域,递归算法是一种强大的工具,尤其在处理树形结构或遍历目录时显得尤为重要。本项目“程序2_delphi_milemut_递归算法”是使用Delphi编程语言实现的一个应用,旨在通过递归方法列出指定目录“C:\Windows\...

Global site tag (gtag.js) - Google Analytics