递归算法及其应用

递归算法及其应用
http://www.mydrs.org  2002-7-4   大榕树


[递归的描述]
  由上面的例子可以看出,一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。因此,在考虑使用递归算法编写程序时,应满足两点: 1 )该问题能够被递归形式描述; 2 )存在递归结束的边界条件。
  递归的能力在于用有限的语句来定义对象的无限集合。用递归思想写出的程序往往十分简洁易懂。

[
2] 给出一棵二叉树的中序与后序排列。求出它的先序排列。
[
分析] 通过对比二叉树的中序与后序排列,我们可以找出根节点及左右子树。同样的,有可以通过对比左子树的中序与后序排列,找出左子树的根节点 …… 可见,该问题能够被递归描述。当找到最后一个根节点时,递归无法再进行下去,这就是递归结束的边界条件。由此可见,递归算法中常常隐含了分治思想。程序如下:
program chu01_3;
  var z,h: string;
  procedure find(a,b:string);
   var
    s,l : integer;
   begin
    l:=length(b);
    if l=1 then Write(b) { 边界条件及递归返回段 }
    else
     begin { 递归前进段 }
      Write(b[l]);
      s:=pos(b[l],a);
      if s-1>0 then find(copy(a,1,s-1),copy(b,1,s-1)); { 递归左子树 }
      if l-s>0 then find(copy(a,s+1,l-s),copy(b,s,l-s)); { 递归右子树 }
     end;
  end;
begin
  Readln(z);
  Readln(h);
  Find(z,h);
  Readln;
end.

[递归的应用]

1.
经典递归
  例如 hanoi 塔问题:经典的递归,原问题包含子问题。有些问题或者数据结构本来就是递归描述的,用递归做很自然。

2.
递归与递推
  利用递归的思想建立递推关系,如由兔子生崽而来的 fibonacci 数列。但递推由于没有返回段,因此更为简单,有时可以直接用循环实现。

3.
分治
  不少分治方法是源于递归思想,或是递归分解 + 合并处理。

4.
回溯
  规模较小的问题用回溯解决比较自然。注意递归前后要保证现场的保存和恢复,即正确的转化问题。

5.
动态规划
  动态规划的子问题重叠性质与递归有某种相似之处。递归 + 动态修改查表是一种不错的建立动态规划模型的方法。

6.
其他
  其他么,就是不好归类。例如表达式处理,排列组合等。附带说一下,用递归来处理打印方案的问题还是很方便的。

[
3] 求把一个整数 n 无序划分成 k 份互不相同的正整数之和的方法总数。
[
分析] 这是一道动态规划题,动态方程如下:
        f[i-1,j]+f[i,j-i]+1 (j mod i=0) and (j div i=1)
   f[i,j]:= f[i-1,j] (i>=j)
        f[i-1,j]+f[i,j-i] else
   s:=f(k,n-k)
本题可以用循环来实现递推 , 也可以考虑用递归求解。主过程如下:

方案一:
Procedure work(I,j:longint; var s:longint);
  Var t:longint;
  Begin
If (i=1) or (j=1) then s:=1
  Else if (i=0) or (j=0) then s:=0
    Else begin
        if (j mod i=0) and (j div i=1) then
             begin
              work(i-1,j,s);
              t:=s;
              work(i,j-1,s);
              s:=s+t+1;
             end
             else if (i>=j) then
                       work(i-1,j)
               else begin
                   work(i-1,j,s);
                   t:=s;
                   work(I,j-1,s);
                   s:=s+t;
                  end;
  End;

方案二: procedure search(v,w,last:byte);
var i:byte;
begin
  if w=0 then inc(count)
  else
   if w=1 then
    if v>=last then search(0,0,0) else
   else for i:=last to v-1 do search(v-i,w-1,i);
end;

  可以看出,方案一的程序较为冗长,消耗栈空间较大;而方案二较为简洁明了,所用的栈空间也较小,效率较高。因此,使用递归算法也有一个优化问题。算法的简洁与否直接制约了程序的可行性和效率。

[
总结]
  递归使一些复杂的问题处理起来简单明了,尤其在学习算法设计、数据结构时更能体会到这一点。但是,递归在每一次执行时都要为局部变量、返回地址分配栈空间,这就降低了运行效率,也限制了递归的深度。因此,在必要的时候可以只使用递归的思想来求解,而程序则转用非递归的方式书写。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值