ITPub博客

首页 > 数据库 > Oracle > 怎样强制退出递归函数

怎样强制退出递归函数

Oracle 作者:rmb14 时间:2012-05-07 13:38:00 0 删除 编辑

  所谓的递归就是函数自己调用自己,于是便构成了循环。既然是循环,就必须给定一个限制条件,否则递归将无限下去,形成死循环。所以使用递归循环的时候,一个很重要的事情就是正确设置退出条件!问题是中途强行退出递归循环困扰了很多人,正如一位学员所言:“不是不想出来,而是出不来!”

  最近我做教程《智慧24点》小游戏时,写了一个递归函数,用来对四个数据进行全排列,每在一个循环层上做出一个排列就尝试四则运算,如果结果等于24,就从递归的这一层上直接返回到调用它的主程序里,而不是用return返回递归的上一层继续递归下去。因为只需要知道这个四个数据能(找一个需要的结论即可)或者不能(遍历后没有需要的结论)组成结果等于24的算式就足够了。

  下面将我的经验与教训(教训是比经验还可贵的反面经验)一同放出。

    


工具/原料

  • win7 + Flash cs5.5 + as3.0

步骤/方法

  1. 1

    错误方法:用“return值”退出循环。

      由于递归的调用是层层嵌套的,所以用return返回时需要一层一层逐级向上返回。换句话说,在return之后,只能确保截断当前层的循环,不能终止递归循环。因主它返回到上一层之后还要在上一层上沿其它“分枝”(树的节点)继续往下递归。

      示例:

      //功能:数组元素全排列

      //参数pre:数组型,初始为空,用来存放结果

      //参数nex:数组型,初始为原始数组

      function arr_all(pre:Array,nex:Array) {

      varj:uint=nex.length;

      if (j==1) {//满足设定的条件后,

      var t=[];

      for (vari:uint=0; i

      t.push(pre[i]);

      }

      t.push(nex[0]);

      returninfo.appendText(" "+pc(t));//用return阻止并返回一个值,但所谓的阻止只是截断了当前的层返回了上层。问题是:返回上层后,递归还在继续进行,没有及时退出循环并进入主程序。这不是我们想要的…………………

      }

      for (var k:uint=0;k

      varp:Array=pre.slice();

      vars:Array=nex.slice();

      p.push(s.splice(k,1));

      arr_all(p,s);//递归…………………

      }

      }

      运行结果:图1

        

      

      递归函数为我们找到了所有的符合条件的结论。而我们只需要第一个,找到了就退出递归。看来,return只是返回了当前循环层的值并往上一层返回。并没有终止递归继教。所以这个方法是错误的。


  2. 2

    无效应用:增加一个标志性参数。

      尝试一下在函数的参数中增加一个标志性的参数,初始化时为真,意思是可以继续循环,当满足条件后再设标志参数为假,再用判断语句结合返回语句阻止循环的继续。主意不错,我们试下:

      还是上面的全排列函数:

      function arr_all(pre:Array,nex:Array, logo:Boolean =true) {

      varj:uint=nex.length;

      if (j==1) {

      var t=[];

      for (vari:uint=0; i

      t.push(pre[i]);

      }

      t.push(nex[0]);

      logo=false//满足条件后,改变标志的值

      returninfo.appendText(pc(t)+" ");//.....out..............

      }

      if (logo =false){return}//用判断语句进行阻止

      

      for (var k:uint=0;k

      varp:Array=pre.slice();

      vars:Array=nex.slice();

      p.push(s.splice(k,1));

      arr_all(p,s,true);

      }

      }

      运行结果叫人大失所望:图2  

        

        

      问题还没解决。看来这个方法说得通,行不通。  

  3. 3

    正确方法:使用位高权重的全局变量!

      我们不得不换个思路,既然在递归函数的内部无法实现想法,那么我们就把目光移到函数体外,另辟蹊径:

      首先,在递归函数之外定义一个全局变量:isGo,布尔型,初始值为真,意思是可以继续循环。

      接着,在递归循环的一开始就设置判断机制,一旦isGo的值为假,就层层阻止,直到退出所有层的循环,从而达到强制退出递归的目的。

      if(isGo==false){

      return

      }

      最后,在递归的“满足条件”代码中增加如下语句:

      isGo =false;

      下面给出修改后的代码:

      var isGo:Boolean=true

      functionarr_all(pre:Array,nex:Array) {

      if(isGo==false){return}

      var j:uint=nex.length;

      if (j==1) {

      var t=[];

      for (var i:uint=0;i

      t.push(pre[i]);

      }

      t.push(nex[0]);

      isGo =false;

      returninfo.appendText(" "+pc(t));//..out........

      }

      for (var k:uint=0; k

      var p:Array=pre.slice();

      var s:Array=nex.slice();

      p.push(s.splice(k,1));

      arr_all(p,s);

      }

      }

      测试结果叫人心花怒放。图3:

        

      本教程要传授的经验是:要想强制退出递归循环,可以通过一个外部变量来实现,只要满足条件就改变这个变量的值,只要这个变量的值变了就层层阻止循环,直到退出递归函数!  

      来自实践的体会,绝对原创的经验。  

         作者:张志晨

          2012.5.5

    END

注意事项

  •   题外话:虽然还有别的办法,如:在满足条件后故意抛出一个异常让程序捕捉,从而强制退出循环,这个不仅麻烦而且运行起来格外耗费资源。另:Break和continue都是循环体内部语句,有阻止和跳过的功能,但权力有限,只对循环体起作用,而对函数体无可奈何。所以强制退出递归循环正宗的,标准的方法是:使用(外部变量isGo ) + (返回语句return)。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22251698/viewspace-1109907/,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
下一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2009-08-02