stdlib的qsort是递归的吗?

时间:2010-07-31 20:43:46

标签: c sorting std qsort

我读过qsort只是一种通用的类型,没有关于实现的承诺。我不知道库如何从平台到平台变化,但假设Mac OS X和Linux实现大致相似,qsort实现递归和/或需要大量堆栈

我有一个大型数组(数十万个元素),我想对它进行排序,而不会让我的堆栈被遗忘。或者,对于大型数组的等价物的任何建议?

9 个答案:

答案 0 :(得分:21)

这是来自BSD的版本,版权所有Apple,可能在某些时候在OS X中使用:

http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/kern/qsort.c

正如Blindy解释的那样,虽然递归深度的上限很小,但它是调用递归的。

这是glibc的一个版本,可能在某些时候在Linux系统中使用:

http://www.umcs.maine.edu/~chaw/200801/capstone/n/qsort.c

调用递归。出于与调用递归限制相同的原因,它可以使用少量固定数量的堆栈来管理其循环递归。

我可以打扰查找最新版本吗?不;;)

对于几十万个数组元素,即使是call-recursive实现也不会调用超过20个级别。在一个不太深入的宏观方案中,除了非常有限的嵌入式设备之外,它们没有足够的内存让你有一个大的排序数组。当N在上面有界时,O(log N)显然是常数,但是它通常是一个可管理的常数。通常32或64倍“小”是“合理的”。

答案 1 :(得分:11)

你知道,递归部分是登录深度。在64级递归(大约64 * 4 =〜256字节的堆栈)中,你可以对一个大小为~2 ^ 64的数组进行排序,即在64位cpu上可以寻址的数组,即147573952589676412928 64位整数的字节数。你甚至不能把它藏在记忆中!

担心重要的事情。

答案 2 :(得分:9)

是的,它是递归的。不,它可能不会使用大量的堆栈。为什么不试试呢?递归不是某种忌 - 它是许多问题的首选解决方案。

答案 3 :(得分:4)

正确实现的qsort不需要超过log2(N)级别的递归(即堆栈深度),其中N是给定平台上最大的数组大小。请注意,此限制适用,无论分区的好坏程度,即最差情况递归深度。例如,在32位平台上,在最糟糕的情况下递归深度永远不会超过32,假设qsort的实现是理智的。

换句话说,如果您特别关注堆栈使用情况,除非您正在处理一些奇怪的低质量实现,否则您无需担心。

答案 4 :(得分:2)

我记得读过这本书:C Programming: A Modern Approach ANSI C规范没有定义如何实现qsort。

这本书写道,qsort实际上可能是另一种排序,合并排序,插入排序以及为什么不冒泡排序:P

因此,qsort实现可能不是递归的。

答案 5 :(得分:1)

使用quicksort,堆栈将以对数方式增长。您将需要很多元素来炸毁堆栈。

答案 6 :(得分:1)

我猜大多数qsort的现代实现实际上都使用了Introsort算法。一个合理编写的Quicksort无论如何都不会打击堆栈(它会首先对较小的分区进行排序,这会将堆栈深度限制为对数增长)。

Introsort更进一步 - 限制最坏情况的复杂性,如果它看到Quicksort运行不正常(递归太多,那么它可能有O(N 2 )的复杂性),它将切换到一个Heapsort,它保证O(N log 2 N)复杂度限制堆栈使用。因此,即使它使用的Quicksort写得很难,切换到Heapsort也会限制堆栈的使用。

答案 7 :(得分:0)

在大型阵列上失败的qsort实现非常破碎。如果你真的很担心我会去RTFS,但是我怀疑任何半好的实现都会使用就地排序算法,或者使用malloc作为临时空间,如果{malloc则返回到就地算法{1}}失败。

答案 8 :(得分:0)

天真快速实施(对于qsort仍然是一种流行的选项)的最坏情况空间复杂度是O(N)。 如果,修改实现以对较小的arary进行排序,首先尾递归优化或使用显式堆栈和迭代然后最坏的情况空间可以归结为O(log N),(这里的大多数答案已经写过了)。因此,如果快速排序的实现没有被破坏并且库没有被不正确的编译器标志破坏,那么你就不会炸毁你的堆栈。但是,例如,大多数支持尾递归消除的编译器都不会在未经优化的调试版本中对其进行优化。使用错误标志构建的库(即,没有足够的优化,例如在您有时构建自己的调试libc的嵌入式域中)可能会使堆栈崩溃。

对于大多数开发人员来说,这永远不会成为一个问题(他们有供应商测试过的libc具有O(log N)空间复杂度),但我认为从时间上关注潜在的库问题是个好主意时间。

更新:这是我的意思的一个例子:libc中的一个错误(来自2000),其中qsort将开始颠覆虚拟内存,因为qsort实现将在内部切换到mergesort,因为它虽然有足够的内存来容纳临时数组。

http://sources.redhat.com/ml/libc-alpha/2000-03/msg00139.html