您的位置:首页 > 其它

递归算法转换为非递归算法

2016-11-20 12:02 351 查看
   递归算法实际上是一种分而治之的方法,它把复杂问题分解为简单问题来求解。对于某些复杂问题(例如hanio塔问题),递归算法是一种自然且合乎逻辑的解决问题的方式,但是递归算法的执行效率通常比较差。因此,在求解某些问题时,常采用递归算法来分析问题,用非递归算法来求解问题;另外,有些程序设计语言不支持递归,这就需要把递归算法转换为非递归算法。

    将递归算法转换为非递归算法有两种方法,一种是直接求值(迭代/循环),不需要回溯;另一种是不能直接求值,需要回溯。前者使用一些变量保存中间结果,称为直接转换法;后者使用栈保存中间结果,称为间接转换法,下面分别讨论这两种方法。

  1. 直接转换法 

  直接转换法通常用来消除尾递归和单向递归,将递归结构用循环结构来替代。

  单向递归:简单的说是指递归的过程总是朝着一个方向进行,如果函数1调用了函数2,而函数2又调用了函数1,则这种情况不属于单向递归。斐波那契数列的递归求解可转用一个迭代法实现。

 斐波那契数列的递归求解:

 int Fib(int n) {

   if(n <= 1) return n;

   else return Fib(n - 1) + Fib(n - 2);

 }

 转化为迭代求解:

int Fib(int n) {

   if(n <= 1) return n;

  int twoBack = 0;

   int oneBack = 1;

   int cur;

  for(int i = 2;i < = n; i++) {

      cur = twoBack + oneBack;

    twoBack = oneBack;

      oneBack = cur;

   }

   return cur;

}

  尾递归函数是以递归调用结尾的函数,是单向递归的特例。它的递归调用语句只有一个,而且是放在过程的最后。当递归调用返回时,返回到上一层递归调用语句的下一语句,而这个位置正好是程序的结尾,因此递归工作栈中可以不保存返回地址;除了返回值和引用值外,其他参数和局部变量都不再需要,因此可以不用栈,直接采用循环写出非递归过程。

  阶乘函数就不是一个尾递归。因为在它收到递归调用的结果后,必须在返回调用前再做一次乘法运算。但是阶乘函数可以转化成一个尾递归函数,例:

阶乘的递归求解:

int factorial(int n)

{

   if(n == 0) return 1;

   else

     {

    int val = factorial(n - 1);

    return n * val;

   }

}

转化为尾递归求解:

int factorial(int acc, int x)

 { //acc传的值为1。

  if(x <= 1) return acc;

  else

     return factorial(x * acc, x - 1);

}

  尾递归的重要性在于当进行尾递归调用时,调用者的返回位置不需要被存在调用栈里。当递归调用返回时,它直接分支到先前已保存的返回地址。因此,在支持尾递归优化的编译器上,尾递归在时间和空间上都比较划算。迭代算法需要一个临时变量,这无疑导致了程序的可读性降低,迭代函数不像递归函数那样需要考虑函数调用的支出,而且对一个线程来说可用的栈空间通常比可用的堆空间要少得多,而递归算法则相对迭代算法需要更多的栈空间!

2. 间接转换法 

  该方法使用栈保存中间结果,一般需根据递归函数在执行过程中栈的变化得到。其一般过程如下:

  将初始状态s0进栈

  while (栈不为空)

  {

  退栈,将栈顶元素赋给s;

  if (s是要找的结果) 返回;

  else {

  寻找到s的相关状态s1;

  将s1进栈

  }

  }

  间接转换法在数据结构中有较多实例,如二叉树遍历算法的非递归实现、图的深度优先遍历算法的非递归实现等等,请读者参考主教材中相关内容。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息