【发布时间】:2011-07-12 03:59:06
【问题描述】:
关于在排序算法或任何算法中使用递归而非递归方法,它的优缺点是什么?
【问题讨论】:
-
一不小心就会导致堆栈溢出
-
一本很好的书,有例子,好处..疑问...pro's...con's...calculating stacksize...等:ISBN:978-1-118-80857-3跨度>
标签: recursion
关于在排序算法或任何算法中使用递归而非递归方法,它的优缺点是什么?
【问题讨论】:
标签: recursion
递归意味着函数重复调用
它使用系统堆栈来完成它的任务。由于堆栈使用 LIFO 方法 当一个函数被调用时,被控制的函数被移动到定义函数的位置,该函数以某个地址存储在内存中,该地址存储在堆栈中
其次,它降低了程序的时间复杂度。
虽然有点题外话,但有点相关。必读。 :Recursion vs Iteration
【讨论】:
递归的名声很差,我总是惊讶于许多开发人员甚至不会接触递归,因为有人告诉他们这是邪恶的化身。
我通过反复试验了解到如果做得正确递归可能是迭代某事物的最快方法之一,它不是一个固定的规则,每个语言/编译器/引擎有它自己的怪癖,所以里程会有所不同。
在 javascript 中,我可以通过引入递归来可靠地加速几乎所有迭代过程,同时减少副作用并使代码更加清晰简洁和可重用。还专家提示它可以解决堆栈溢出问题(不,你不要禁用警告)。
我个人的优点和缺点:
优点:
- Reduces side effects.
- Makes code more concise and easier to reason about.
- Reduces system resource usage and performs better than the traditional for loop.
缺点:
- Can lead to stack overflow.
- More complicated to setup than a traditional for loop.
里程会因语言/编译器/引擎而异。
【讨论】:
我们应该在以下场景中使用递归:
递归将保存多次遍历。如果我们可以像这样划分堆栈分配,它将很有用:
int N = 10;
int output = process(N) + process(N/2);
public void process(int n) {
if (n==N/2 + 1 || n==1) {
return 1;
}
return process(n-1) + process(n-2);
}
在这种情况下,在任何给定时间只会分配一半的堆栈。
【讨论】:
任何使用递归实现的算法也可以使用迭代来实现。
例如,与迭代相比,使用递归更容易解决河内塔问题。
【讨论】:
在某些情况下,您必须在递归似乎对您有利的问题中放弃递归,这是因为对于您的递归必须发生数千次的问题,这会导致 stackoverflow 错误,即使您的代码没有陷入无限递归。大多数编程语言将您限制为多次堆栈调用,因此如果您的递归超出此限制,那么您可能会考虑不使用递归。
【讨论】:
大多数问题自然是通过递归来表达的,例如斐波那契、合并排序和快速排序。在这方面,代码是为人类而不是机器编写的。
迭代解决方案通常依赖于不同的临时变量,这使得代码难以阅读。这可以通过递归来避免。
递归不是堆栈友好的。当递归设计不当或不支持尾部优化时,堆栈可能会溢出。
【讨论】:
在大多数情况下,递归速度较慢,并且占用了更多的堆栈。递归的主要优点是,对于像树遍历这样的问题,它使算法更容易或更“优雅”。 查看一些比较:
【讨论】:
所有算法都可以递归定义。这使得可视化和证明变得更加容易。
某些算法(例如,Ackermann Function)不能(很容易)迭代地指定。
如果无法执行tail call optimization,递归实现将使用比循环更多的内存。虽然迭代可能比无法优化的递归函数使用更少的内存,但它的表达能力有一些限制。
【讨论】:
开始:
优点:
缺点:
【讨论】:
我个人更喜欢使用迭代而不是递归函数。特别是如果您的函数具有复杂/繁重的逻辑并且迭代次数很大。这是因为每次递归调用调用堆栈都会增加。如果您的操作太大并且还会减慢进程,它可能会导致堆栈崩溃。
【讨论】: