第12章 非递归化
本章主要介绍下列内容(教材第四章)
1. 问题引入(递归问题)
2. 栈
3. 递归过程的改写
4. 小结
课时分配:第1、2节讲授三个学时,第3、4节讲授三个学时,上机三小时
重点、难点:递归过程的改写
第一节 问题引入
一、使用递归的好处
使所描述的算法或程序简洁明了。
二、为什么要将递归算法非递归化?
1.有些语言不支持递归功能。
2.当问题规模太大时,递归算法所耗时间和空间都较非递归算法多。
3.递归所使用的空间主要由编译程序自动分配堆栈,空间较小;非递归所使用的空间
可由程序自行在堆动态空间中申请,容量大。
三、为什么教材主要讨论直接递归的非递归化问题?
因为间接递归大多可转化成直接递归。例如:
Var
a,b,n;integer;
Procedure P2(Var x:integer);forword;
Procedure P1(y:integer);
begin
y:=y*2+10;b:=y Div 30;P2(y);
end
Procedure P2;
Begin
If x<400 then begin n:=n+1;P1(x) end
End;
Begin
Write(‘input a=’);readln(a);n:=0;P2(a);
Writeln(‘N=’,n:3,‘,B=’,b:4)
End.
运行:
Input a=21
N=4,B=16
Input a=-156
N=8,B=938
以上两过程即是间接递归调用,可将其合为如下的直接递归调用过程。
Procedure P2(Var d:integer);
Var y:integer;
Begin
if x<400 then
Begin
n:=n+1;
y:=x;y:=y*2+10; 可优化成y:=x*2+10;
b:=y Div 30;
P2(y)
End
End;
还可进一步优化成:
Procedure P2(Var d:integer);
begin
if x<400 then
begin n:=n+1;x:=x*2+10;b:=x Div 30;P2(x);end
end;
四、递归与循环可以相互转换,见P89。 ①尾部递归
五、顺序搜索的递归和非递归算法,见P89。 ②函数
六、递归问题(略讲)
第二节 栈
栈是改写递归算法和理解递归算法的工具。理解实例可介绍《数据结构》教材中河内塔
部分补充页码!
一、尾递归及其非递归化(见P93)
变成非递归时可不用栈。
1.定义
2.方法
二、非尾递归的非递归化
要用栈这种数据结构来实现,每一个需保存的变量设置一个栈。局部变量、值参量和返
回点都需栈,但全局变量和变参不要栈。
1.关键点——递归过程的开始点、结束点和返回点。
2.以非尾递归算法Tower的非递归化为例说明一般步骤和方法。见P95-P97
自学
第三节 递归过程的改写
该节进一步总结非递归化方法,请学生自学方法。
一、Tower3在Tower2基础上减少了四个局部变量。P99
二、99-100页Quick算法的非递归化请同学自学。
三、Permu的非递归化要重点介绍——见P100-101。
这是递归调用语句出现在循环体中的情形,这种情况要将循环语句变形成if+goto形式
后再非递归化。
四、哪些量要进栈保存?
有关原则见P102。
第四节 小 结
一、递归问题的非递归化步骤
二、递归函数转化成过程后再非递归化
三、间接递归转化成直接递归后再非递归化
四、尾递归一般用While或repeat实现非递归化,其它情况用if+goto实现。
五、一个补充实例:
写出递归函数 ? ? ? ?
??
?
≥
<+=
2)4(*2
21)(
nnfnf
nnnf 的非递归求值过程。
原递归算法之变形:
Procedure exmp(n,Var f);
Var u1,u2:integer;
begin
0:
if n<2 then [f:=n+1;goto 3];
exmp(n Div 2,u1);
1:
exmp(n Div 4,u2) exmp(n Div 4,f);
2: 2:
f:=u1*u2 f:=u1*f;
3:
end;
实际上,将非递归过程还原成函数非常容易。
非递归算法:
Procedure exmp(n,Var f);
Var r:记录(rd,Pn,u1);s:栈(r型记录数组)
begin
初始化栈S;
0:if n<2 then [f:=n+1;Goto 3];
r.rd:=1;r.Pn:=n;Push(s,r);n:=n Div 2;Goto 0;
1:n:=Top(s,Pn);Top(s,u1):=f;r.rd:=2
?
Push(s,r);n:=top(s,Pn) Div 4;Goto 0;
2:pop(s);f:=Top(s,u1)&f;pop(s);
3:if not empty(s) then Goto Top(s,rd)
end;{最后结果存在f中}
在黑板上举n=12为例进行演示!
另一个更简单方法由95级陈强和96级彭磊给出:
int f(int n)
{int f1;
栈s置空;n进栈;f1:=1;
while(s)
{pop(s,n);if(n==1)f1=f1+f1;
if(n>1){push(s,n/2);push(s,n/4);}
}
return f1;
}
或:
int ff(int n)
{int I,f[n];
f[0]=1;f[1]=2;
for(i=2;i<=n;i++)f[i]=f[i/2]*f[i/4];
return f[n];}
这是纯递推办法,虽效率低,但直观易编程!
以FeiboNacci数列第n项的求法引入这个算法:
①根据通项公式计算第n项之值;
②直接递推求解
由此看来,函数的非递归化因为是求值,比过程的非递归化更简单。
③递归方程:
?
?
?
???
?
>
=
=
=
1*
12
01
42
nff
n
n
f
nn
n 的解法见补充材料(学报待发)。
关于 P 与 NP理论简介,可根据时间或学生实际略讲或不讲。
一、问题分类
1.无法写出算法的问题——难题
2.有以多项式为界的算法存在的问题——P类问题
3.介于前两类之间的问题——存在指数阶算法,但不知道是否存在多项式算法(NP问
题)
二、概述
1.问题
2.问题实例
3.解决某问题的算法
4.问题实例的大小
5.将问题实例转化(映射)成字符串进行研究
6.两种难的问题
7.研究“难”解问题的两种方法
(1)证明一个问题是“难”的;
(2)研究难问题之间的关系,这有助于算法设计,主要方法是“归约”。
本章其它部分从略。