递归算法与栈.docVIP

  • 29
  • 0
  • 约6.27千字
  • 约 7页
  • 2017-10-03 发布于重庆
  • 举报
递归算法与栈

[递归算法及在计算机中的实现] 1、 例1、用递归算法把任一给定的十进制正整数(=32000)转换成八进制数输出,程序如下: var m:integer; procedure tran(n:integer); {递归过程} var k:integer; begin k:=n mod 8; n:=n div 8; if n0 then tran(n); write(k:1) end; begin {主程序} write(input m:); readln(m); write(m,=(); tran(m); writeln()8); readln; end. 输入:m=765 {下划线表示输入} 765=(1375)8 例2、用递归算法求N阶乘(N!=1*2*3*……*N,N20); var n:integer; function f(n:integer):longint; {递归函数,N=20时,超过maxlongint} begin if n=0 then f:=1 else f:=n*f(n-1) end; begin {主程序} write(input n:); readln(n); write(n,!=,f(n)); end. 2、 计算机执行递归算法时,是通过栈来实现的。具体说来,就是在(递归过程或递归函数)开始运行时,系统首先为递归建立一个栈,该栈的元素类型(数据域)包括值参、局部变量和返回地址;在每次执行递归调用语句时之前,自动把本算法中所使用的值参和局部变量的当前值以及调用后的返回地址压栈(一般形象地称为“保存现场”,以便需要时“恢复现场”返回到某一状态),在每次递归调用结束后,又自动把栈顶元素(各个域)的值分别赋给相应的值参和局部变量(出栈),以便使它们恢复到调用前的值,接着无条件转向(返回)由返回地址所指定的位置继续执行算法。 具体到上面的例1中,当遇到递归调用tran(n)时,系统首先为后面的递归调用建立一个含有3个域(值参n,局部变量k和一个返回地址)的栈;在每次执行递归调用tran(n)前,系统自动把n和k的当前值以及write(k:1)语句的开始位置(即调用结束后的返回地址)压栈;在每次执行到最后的end语句(即一次递归调用结束)后,又自动把栈顶的与n和k对应的值分别赋给n和k(出栈),接着无条件转向write(k:1)语句的开始位置继续向下执行程序。 ? 3、 早期操作系统DOS的内核是限制只能使用640K内存(当时的机器内存也很小),在此之上的BP运行时,可用的所有内存空间最大也只能为640K,其中程序代码、常量、变量和堆栈(局部变量、子程序参数、返回地址;即递归中的栈)各占64K,在BP中的OPTIONS菜单的MEMORY SIZE子菜单中可以修改STACK SIZE至多到64K(一般设置为65520),可以解决很多递归程序遇到的栈溢出错误。 640K以内(64K以上)的多余空间,方法是手工开辟一个栈空间模拟系统处理递归的实现方法,这样就可以把一个递归过程转换成非递归过程,一方面可以进一步加深对栈和递归的理解,另一方面也可以解决一些递归无法解决的问题。但带来的问题是程序会很复杂。 [递归转换为非递归] P是一个递归算法,假定P中共有m个值参和局部变量,共有t处递归调用P的语句,则把P改写成一个非递归算法的一般规则为: 1、? S,用来保存每次递归调用前值参和局部变量的当前值以及调用后的返回地址。即S应该含有m+1个域,且S的深度必须足够大,使得递归过程中不会发生栈溢出。 2、? t+2个语句标号,其中用一个标号标在原算法中的第一条语句上,用另一个标号标在作返回处理的第一条语句上,其余t个标号标在t处递归调用的返回地址,分别标在相应的语句上。 3、? (1)?????? (2)?????? (3)?????? 4、? (1)?????? (2)?????? m个域的值分别赋给各对应的值参和局部变量; 3)?????? 5、? S栈的成分类型(元素)相同的变量,作为进出栈的缓冲变量,对于递归函数,还需要再增设一个保存函数值中间结果的临时变量,用这个变量替换函数体中的所有函数名,待函数结束之前,在把这个变量的值赋给函数名返回。 6、? 7、? n处),则应首先把它拆成n条赋值语句,使得每条赋值语句只包含一处递归调用,同时对增加的n-1条赋值语句,要增设n-1个局部变量,然后按以上六条规则转换成非递归函数。 [应用举例] 3、1中的递归过程改写成非递归过程。 procedure tran(n:integer); {非递归过程} label 1

您可能关注的文档

文档评论(0)

1亿VIP精品文档

相关文档