“就地”MSD基数排序,堆栈空间和堆栈溢出

时间:2013-11-09 09:36:59

标签: algorithm sorting stack-overflow radix-sort in-place

我真的很困惑the "in-place" MSD radix sort算法:

  

然后使用下一个数字递归处理每个bin,直到所有数字都被用于排序。

我很困惑,因为在我看来,递归意味着O(n)堆栈空间,其中<​​em> n 是最长字符串的长度(位数),对吗?

在我看来,避免堆栈溢出的唯一方法是使用堆空间 - 但随后算法不再是任何定义的“就地”。

那么,如何才能就地进行MSD基数排序呢?

2 个答案:

答案 0 :(得分:1)

我认为术语“就地MSD基数排序”有点误导,因为正如你所指出的那样,它不是在“就地”的严格定义下的就地算法。这里的“就地”术语很可能是指与LSD基数排序不同的是,该算法不需要辅助数组来临时存储原始输入数组中的元素。

您是正确的,MSD基数排序的空间使用量与最大输入数字中的位数成正比。为了简化符号,让我们有n个输入数组的长度,U是数组中最大的数字。然后,MSD基数排序的运行时间为O(n log U),因为数字U中的位数是O(log U)。 O(log U)是一种非常非常缓慢增长的功能。作为参考,宇宙中的原子数约为10 80 ,约为2 240 。因此,如果您要对由任何物理过程生成的数字进行排序,则递归深度最多为240,而大的则绝对可以管理。

如果你正在排序真正的大数字 - 例如,有数千和数千位的数字 - 那么你就是担心要烧掉堆栈了。但是,我认为如果你有一个很好的MSD基数排序实现,这种情况发生的可能性极小。快速排序中有一个标准优化 - 看起来很像MSD基数排序 - 而不是进行两次分支递归调用,而是在两个范围中较小的一个上进行一次递归调用以进行排序,然后将堆栈帧从初始调用回收到排序较大的范围。 (这实际上是一种尾部呼叫消除)。现在,假设您将此应用于MSD基数排序。由于每个新创建的堆栈帧都在两个范围中较小的一个上进行排序,因此可以保证每个新堆栈帧中的元素数量是前一个堆栈帧的一半。因此,堆栈可以达到的最大深度为O(log n) - O(log U)。为了使你的堆栈爆炸,无论堆栈大小如何,你都需要一个真正的天文大型输入数组。

总结:你是对的,算法不到位。但是,由于堆栈深度在初始实现中为O(log U),在优化实现中为O(log n),因此除非您有一个简单的实现并且真正巨大的巨大,否则您不必担心这一点。输入。

答案 1 :(得分:0)

此算法就位,因为它交换来自阵列两端的两个值。一个例子是:

{110,010,111,000,011}

0 bin位于左侧,而1 bin位于右侧。从MSD开始,一步一步地排序如下:

{|110,010,111,000,010|}
{011|010,111,000|110}
{011,010|111,000|110}
{011,010,000||111,110}

这可以在该示例中在O(3n)时间内完成,其简化为O(n)。唯一需要的额外内存是交换空间足够大的一个元素。

相关问题