栈与递归的关系

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

栈与递归的关系

姓名:郭小兵

学号:1007010210

专业:信息与计算科学院系:理学院

指导老师:彭长根

2012年10月17日

栈与递归的关系

郭小兵

摘要递归是计算机科学中一个极为重要的概念,许多计算机高级语言都具有递归的功能,对于初学计算机者来讲,递归是一个简单易懂的概念,但真正深刻理解递归,正确自如的运用递归编写程序却非易事,本文通过一些实例来阐述递归在计算机内的实现及递归到非递归的转换,也许使读者能加深对递归的理解。

关键词栈递归非递归

引言递归是一种程序设计的方式和思想。计算机在执行递归程序时,是通过栈的调用来实现的。栈,从抽象层面上看,是一种线性的数据结构,这中结构的特点是“先进后出”,即假设有a,b,c三个元素,依次放某个栈式存储空间中,要从该空间中拿到这些元素,那么只能以c、b、a的顺序得到。递归程序是将复杂问题分解为一系列简单的问题,从要解的问题起,逐步分解,并将每步分解得到的问题放入“栈”中,这样栈顶是最后分解得到的最简单的问题,解决了这个问题后,次简单的问题可以得到答案,以此类推。分解问题是进栈(或者说压栈)的过程,解决问题是一个出栈的过程。

科学家对栈与递归都做了很多深入的研究,研究表明“递归算法

和栈都有后进先出这个性质,基本上能用递归完成的算法都可以用栈完成,都是运用后进先出这个性质的”这个性质可用于进制的转换。与汇编程序设计中主程序和子程序之间的链接及信息交换相类似,在高级语言编制的程序中,调用函数和被调用函数之间的链接及信息交换需过栈来进行。递归是计算科学中一个极为重要的概念。许多计算机高级语言都具有递归的功能,本文将通过一些是例来阐述递归在计算机内的实现及递归到非递归的转换,也许能加深对递归的理解。递归是某一事物直接或间接地由自己完成。一个函数直接或间接地调用本身,便构成了函数的递归调用,前者称之为直接递归调用,后者为间接递归调用。递归会使某些看起来不容易解决的问题变得容易解决。特别当一个问题蕴含递归特性且结构比较复杂时,采用递归算法往往要自然、简洁、清晰,写出的程序较为简短。在很多时候,程序结构简单,可读性好甚至比运行时间更重要,所以掌握递归算法也就存在一定的必要性。但许多人,特别是计算机专业低年级和一些初学者,往往觉得递归很难理解。为了更好地掌握他,了解递归过程的操作原理就更有意义了。

一、栈与递归的关系

递归是一种重要的算法设计方法。递归函数的特点在于,在一汁算该函数时需直接或问接地调用该函数自己。这种递归函数在计算机科学和数学等领域有着,h泛的应用。

栈是一种线性表,对于它所有的插入和删除都限制在表同一端进行。这一端称为栈顶,另一端称为栈底。栈又称为“后进先出表”,即后进的先出,先进的最后出。

栈和递归是可以相互转换的,当编写递归算法时,虽然表面上没有使用栈,但系统执行时会自动建立和使用栈。栈和递归有着本质的区别:递归函数由很多栈组成,也就是说栈是程序函数中的一个元素,递归是函数的一种运行方式。

二、举例分析

举例来说,计算n的阶乘的问题,可以利用阶乘的递推公式n!:n*(n—1)!,对该问题进行分解,把计算n的阶乘问题化为等式右边涉及规模较小的同类问题(n—1)的阶乘的计算。这种分而治之的递归分析方法,对很多具有复杂数据结构的问题是强有力的。设函数f(n)=n!,则递归函数f(n)可表示为:

fc n)={二*f。n一。) ‘0:‘≥

例:采用递归算法求解正整数n的阶乘(n!)。

函数f(n)=n!,递归函数“n)可表示为:

f(n)=f’ (n=o)

L n*f(n—1) (n>O)

在这里n=O为递归终止条件,使函数返回l,n>O实现递归调用,由n的值乘以f(n—1)的返回值求出f(n)的值。

用C++语言编写出求解n!的递归函数为:

long f(int n)

{

if(n==O)

retum l;

else

retum n*f(n—1);

}

当从主程序或其他函数非递归调用此阶乘函数时,首先把实参的值传送给形参n,同时把调用后的返回地址保存起来,以便调用结束之后返回之用;接着执行函数体,当n等于O时则返回函数值l,结束本次非递归调用或递归调用,并按返回地址返回到进行本次调用的调用函数的位置继续向下执行,当n大于O时,则以实参n—l的值去调用本函数(即递归调用),返回n的值与本次递归调用所求值的乘积。因为进行一次递归调用,传送给形参n的值就减l,所以最终必然导致n的值为O,从而结束递归调用,接着不断地执行与递归调用相对应的返回操作,最后返回到进行非递归调用的调用函数的位置向下执行。

假定用f(4)去调用f(n)函数,该函数返回4*“3)的值,因返回表达式中包含有函数f(3),所以接着进行递归调用,返回3*f(2)的值,依次类推,当最后进行f(O)递归调用,返回函数值l后,结束本次递归调用,返回到调用函数f(O)的位置,从而计算出l*f(O)的值l,即l*f(O)=l*l=l,作为调用函数f(1)的返回值,返回到2*f(1)表达式中,计算出值2作为f(2)函数的返回值,接着返回到3*f(2)表达式中,计算出值6作为f(3)函数的返回值,再接着返回到4*f(3)表达式中,计算出f(4)的返回值24,从而结束整个调用过程,返回到调用函数f(4)的位置继续向下执行。

在一个迷宫中,中间的每个方格位置都有四个可选择的移动方向,而在四个顶点只有两个方向,并且每个顶点的两个方向均有差别,

每条边线上除顶点之外的每个位置只有三个方向.并且也都有差别。为了在求解迷宫的算法中避免判断边界条件和进行不同处理的麻烦,使每一一个方格都能够试着按四个方向移动,可在迷宫的周围镶上边框,在边框的每个方格里填一卜l,作为墙壁,这样就需要用一个[m+2][n+2]大小的二维整型数组(假定用maze表示数组名)来存储迷宫数据。

当从迷宫中的一个位置(称它为当前位置)前进到下一个位置时,下…‘个位置相对于当前位置的位移量(包括行位移量和列位移量)随着前进方向的不同而不同,东、南、西、北(即右、下、左、上)各方向的位移量依次为(O,1),(1,O、),(O,一1)和(一l,O)。假定用一个4×2的整型数组move来存储位移量数据,则move数组的内容如右面所示:其中move[O]~一e[3]依次存储向东、南、西、北每个方向移动一步的位移量。如moVe[1][O]和move[1][1]分别为从当前位置向南移动一步的行位移量和列位移量,其值分别为l和O。

在求解迷宫问题时,还需要使用一个与存储迷宫数据的maze数组同样大小的辅助数组,假定用标识符mark表示,用它来标识迷宫中对应位置是否被访问过。该数组每个元素的初始值为O,表示迷宫中的所有位置均没有被访问过。每访问迷宫中一个可通行的位置时,都使mark数组中对应元素置l,表示该位置已经被访问过,以后不会再访问到,这样才能够探索新的路径,避免重走已经走不通的老路。

为了寻找从入口点到出口点的一条通路,首先从入口点出发,按照东、南、西、北各方向的次序试探前进,若向东可通行,同时没有

相关文档
最新文档