尾递归以及优化

参考文章:

尾递归与Continuation

浅谈尾递归的优化方式(这篇和上面那篇都出自知乎三大编程大佬之一:赵劼)

递归与尾递归总结

什么是尾递归?

一.  先看一个来自知乎的通俗例子

  • 尾递归:
    function story() {
    从前有座山,山上有座庙,庙里有个老和尚,一天老和尚对小和尚讲故事:story()
    // 尾递归,进入下一个函数不再需要上一个函数的环境了,得出结果以后直接返回
    }
  • 非尾递归:
    function story() {
    从前有座山,山上有座庙,庙里有个老和尚,一天老和尚对小和尚讲故事:story(),小和尚听了,找了块豆腐撞死了
    // 非尾递归,下一个函数结束以后此函数还有后续,所以必须保存本身的环境以供处理返回值。
    }

二. 递归和尾递归

  • 我们都知道,在递归操作中,可能要通过栈来保存一些当前函数的信息。如果一个函数递归非常多次,就很可能引发栈溢出。
  • 尾递归是:如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。尾递归函数的特点是在回归过程中不用做任何操作(也就是说可以不用保存函数的信息),这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码。
  • 尾递归就是从最后开始计算,每递归一次就算出相应的结果。也就是说,函数调用出现在调用者函数的尾部。因为是尾部,所以根本没有必要去保存任何局部变量。直接让被调用的函数返回时越过调用者,返回到调用者的调用者去。
  • 尾递归就是把当前的运算结果(或路径)放在参数里传给下层函数,深层函数所面对的不是越来越简单的问题,而是越来越复杂的问题,因为参数里带有前面若干步的运算路径。
  • 举个栗子:
//直接递归求链表的长度 
int GetLengthRecursive(linklist head)
{
     if(head->next == NULL)
        return 0;
     return (GetLengthRecursive(head->next) + 1);
}

//采用尾递归求链表的长度,借助变量acc保存当前链表的长度,不断的累加 
int GetLengthTailRecursive(linklist head,int *acc)
{
     if(head->next == NULL)
       return *acc;
     *acc = *acc+1;
     return GetLengthTailRecursive(head->next,acc);
}

猜你喜欢

转载自blog.csdn.net/weixin_39731083/article/details/81915678