递归与非递归的转换
Posted 4nc414g0n
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归与非递归的转换相关的知识,希望对你有一定的参考价值。
递归
用递归解决的三类问题
:
- 数据的定义是按递归定义的。(Fibonacci函数,n的阶乘)
- 问题解法按递归实现。(回溯)
- 数据的结构形式是按递归定义的。(二叉树的遍历,图的搜索)
递归相对于循环迭代的问题:
- 递归太深,导致栈溢出(
线性递归
)- 性能问题(现在编译器优化越来愈好,此问题在相对变得不那么重要)
以斐波那契数列为例
线性递归
long long Fib(size_t N) { if(N < 3) return 1; return Fib(N-1) + Fib(N-2); }
每次调用时是先调用Fib(n-1),再调用Fib(n-2),所以图中第一列是最先被调用的,由于空间不累计性,空间复杂度按最多的第一列算O(N)
在调用递归调用Fib(n-1)的时候,Fib(n-2)还没有执行,需要保存前面的状态,因此开销较大
尾递归
int Fib(int n, int ret1, int ret2) { if (n == 0) return ret1; else return Fib(n-1, ret2, ret1 + ret2); }
- 尾递归的判断标准是函数运行最后一步是否调用自身,而不是是否在函数的最后一行调用自身
- 一般尾递归在写法上主要会把上次运行的结果通过参数进行传递
- 空间复杂度O(1)
尾调用的重要性在于它可以不在调用栈上面添加一个新的堆栈帧——而是更新它,如同迭代一般。尾递归因而具有两个特征: 调用自身函数(Self-called); 计算仅占用常量栈空间(Stack Space)。 而形式上只要是最后一个return语句返回的是一个完整函数,它就是尾递归。
递归转换为非递归
循环迭代
尾递归
例子
:数据结构----排序 中的归并排序非递归解法
栈或队列+循环迭代
线性递归
例子
:数据结构----排序 中的快速排序非递归解法
以上是关于递归与非递归的转换的主要内容,如果未能解决你的问题,请参考以下文章