递归问题与递归结构(五)

再讨论几个递归函数的结构

汉诺塔问题是计算机中的一个经典问题,为讨论方便先表述如下:

        三根立柱分别用A、B、C表示,假设A上套有n个中空圆盘,自顶向下由小到大依次叠放。如果按以下规则移动圆盘,一次只能移动一个,且移动过程中小圆盘只能位于大圆盘之上,问把这n个圆盘全部移到立柱B上需要的多少步?当然还有其它的一些问法,比如要多少时间或者要如何实现等等。但一般对这些问题的解答都是建立在模拟出整个移运过程的基础之上的。现给出模拟整个移动过程的算法:

void  MoveTower(int n,  char  src,  char dst,   char  tmp)

{

      if( n>0 )

      {

           MoveTower( n-1,  src,  tmp,  dst );

           MoveSingleDisk( src,  dst );

           MoveTower( n-1,  tmp,  dst,  src );

      }

}

先简单说明如下:用字符表示的三根立柱A、B、C在调用过程中,分别作为MoveTower的三个参数传入到函数体内参与相关运算。参数src 表开始移动时圆盘离开的那根立柱,参数dst表示圆盘移动的最终的目标立柱,参数tmp表示整个移动过程中起临时中转作用的立柱。

      现在令人感兴趣的是,这是一个排列问题还是一个子集问题?

     先抛开上面的算法,直接对圆盘的移动进行思考,我们要求的实际上是类似这样的一个序列:(A->B),(A->C),(B->C)......。为了使分析更具有一般性,这里假设现在处于整个移动过程的中间某一点。如果我们完全不知道下一步该移动哪个立柱上的圆盘,才能按规则最终把A上的所有盘都移到B上,那么当前可以做的就是把各种可能都偿试一下。而实际上我们每一步可偿试的方案一般都有以下6种:A->B, A->C, B->C, B->A, C->A, C->B (在一些临界情况下,可能会少几种选择),每一种选择又会导致不同的后果。此过程是递归的。而最后一定会找到一种方案在合乎规则的情况下,实现所有圆盘都被移动到B上这一目标。3根立柱,每步都有6种选择方案,因此这一递归过程明显是一个排列的过程。

      正如前面讨论的那样,用递归方法求解汉诺塔必会产生一棵递归树,递归树的每个结点表示一种决策或选择。从第一个圆盘(最顶端的圆)的移动开始到最后一个圆盘(同样是最顶端的圆盘)移动结束为止,其整个过程是一个从根结点到叶子结点的正向搜索过程,这是一个排列递归。但这一过程带有相当的盲目性,因为每一步递归都会面临可能的6种选择,运算效率是不高的。正如之前解决这类问题常用的方法那样,从结果倒推回去则会大大提高效率,上面的算法正是建立在这一思想的基础之上的。它假设,如果要实现所有圆盘从A移动到B这一目标,n个圆盘中必须要先将最底层的圆盘移动到B上,然后再将所有n-1个圆盘移到B上,而对这n-1个圆盘的移动来说,可以用同样的算法过程来描述。递归结构找到。这种方法的好处就在于,任何的当前局面下,下一步的选择都是明确的,是唯一的,从而避免了大量盲目性的搜索。

      小结一下,从问题本身看,求解输出结果无疑会构成一种排列性的递归,但由于算法采用了自底向上的反向递推方式,使得每一步的选择都是唯一的,这就导致了我们可以这样来看整个递归决策过程:每一个决策要么包含在另一个决策中,是它的子决策,要么不包含在另一个决策中。这明显带有子集递归的特点,所以以上的代码最终呈现出了子集递归的特点。

      在这里可以比较一下数学中递归方程的求解过和程序中的递归函数过程:

      数学中的递推方式一般是从最简单的初始值开始,依次向n迭代。而程序中的递归函数往往是根据分治法而来,分治法的思想是把大问题分解为同构的更小规模的子问题来处理,并依次递归,所以自然会呈现出与数学公式迭代方向相反的递推模式,而有些问题中这会导致盲目搜索的出现,出现这种情况时,如果我们在使用分治法思想时,能够从初始条件开始递减问题规模,则有可能得到更高效的算法。


二分法搜索(Binary Search)

       在一个有序的数列中用二分法进行查找,也可以用递归过程来实现。那么这一递归过程是排列型的还是子集型的?二分法查找过程必会生成一个递归树,每一个结点的决策对应着这样一个问题,被查找数包含在相应集合中吗?所以代码会呈现出子集递归的特点。

       稍微辨明下查找二叉树与二分法搜索形成的决策树之间的区别。


归并排序

     归并排序是另外一种递归决策过程,决策树的每个结点为一个有序数列,数列中的每个元素,要么会被分(包含)到左子树中,要么不会(而必被分到右子树中),所以代码会呈现子集递归的特点。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值