排序算法中的递归 - 总是坏的?

时间:2013-01-30 14:44:48

标签: c++ algorithm recursion mergesort

Mergesort,quicksort可能是最知名的nlogn排序算法。在大多数情况下,他们的解释和c ++代码示例包含递归。但据我所知,当数据量很大时,我们会对递归进行理解,这会导致堆栈溢出的风险很大。那么忽略关于排序算法的递归解释是否合理是不合理的呢?

4 个答案:

答案 0 :(得分:10)

  

但据我所知,当数据量很大时,我会理解递归,我们会冒很大的堆栈溢出风险。

这取决于几件事:

    这些天
  • Tail calls几乎总是被优化,所以即使你递归O(2^N)次,你也永远不会用尾递归命中堆栈溢出(算法仍然很慢,但它不会溢出堆栈)。
  • 大多数排序算法都会递归Log2(N)次。这可以达到每TB数据排序的40个级别 - 不足以溢出任何能够在其内存中保存数TB数据的堆栈。
  

忽略关于排序算法的递归解释是否合理,以至于无法在现实生活中使用?

不,忽略这些解释是不合理的:如果算法在逻辑上是递归的,那么最佳解释也将是递归的。即使您使用循环使用动态分配的堆栈来实现算法以避免堆栈溢出,算法的性质仍将是递归的,因此理解正在发生的事情的最佳方式是假装进行递归调用。

答案 1 :(得分:7)

使用O(n log n)排序算法,递归算法引起的调用堆栈高度通常为O(log n)(假设在每次递归迭代时相对平衡的问题大小划分)

在最糟糕的情况下,在一个天真的实现中,当数组已经排序时,总是使用最后一个元素作为数据透视,这种情况会发生异常。在这种情况下,你将有一个O(n^2)运行时间和招致调用堆栈高度为O(n)

(如果它可以帮助你想象:这有点类似于使用比BFS更少空间的DFS背后的基本原理 - 前者只跟踪一次调用堆栈中的一个“搜索路径”,而后者跟踪所有这些)

答案 2 :(得分:3)

O(n logn)算法中,我们通常会查看递归的log2(n)级别。

举一个具体的例子log2(1,000,000,000) = 30,所以几乎不存在堆栈溢出的主要风险。

如果允许递归深度增长,例如O(n),事情就会出现问题。可扩展的算法需要确保不会发生这种情况。

答案 3 :(得分:0)

正如其他人所指出的,堆栈的深度等于递归的最深层,通常是订单log(n)。

递归的“问题”通常是进行方法调用和传递参数所涉及的开销。例如,考虑一个因子方法

int factorial(int k) {if(k == 1)返回1,否则返回k * factorial(k-1);}

如果你用n = 21来调用它,那么你会进行20次乘法运算,但是你也需要设置和返回20次方法调用的开销 - 还有很多工作要做。如果您确实想使用递归算法,您可以设置私有堆栈并使用while循环来实现算法,而无需大量(相对昂贵的)方法调用。当然,改进(如果有的话)将取决于语言。