我一直在阅读合并排序,到目前为止,我已经看到了三个主要的不同版本:
首先,为什么它们都被认为是相同的算法?是因为主要想法是将两个排序列表合并为一个排序列表吗?
第二,什么时候应该使用?就地抽象不会进行递归调用,并且我听说过这是一件好事,因为它避免了深度调用堆栈(例如,我看到人们在没有递归的情况下不停地实现Quicksort)。这是否意味着就地使用最少的内存?
TL; DR抽象就地,自上而下和自下而上合并排序有什么区别?
答案 0 :(得分:1)
是的,mergesort的所有变体都使用相同或类似的合并阶段。
没有(AFAIK)真正有效的就地合并排序,现有的合并排序非常复杂且速度相当差。
自上而下和自下而上的实现非常接近,您可以选择任何。递归级别受log2(n)的限制,因此深度堆栈是不可能的
还有一些mergesort类型 - 例如,自然mergesort适用于部分排序的数据集。
答案 1 :(得分:1)
这里有一个小小的误解:抽象就地合并不是一个mergesort,它是用于将两个数组合并在一起的例程。链接描述的两种风格是自下而上和自上而下的合并。它们是完全相同的算法,完全相同compares
和swap
完成。但是实现依赖于每种方法的不同方法,这就是他们的名字来源。
抽象就地合并
合并排序的问题是执行它所需的额外空间。制定它的所有方案都非常复杂并且不太实用。这个方案只是一个良好的就地合并类型的抽象,并且这个合并的实现很容易。但它不是就地,仍然使用这个额外的O(n)内存。
自上而下合并
这是最常见的一个。它通常依赖于递归,并使用自上而下的方法。即:从长度为n的数组开始,递归地对两半进行排序,然后将它们合并在一起。我们称之为自上而下,因为我们从长度为n的数组开始并减少问题,直到得到大小为1的数组。
自下而上合并
mergesort的第二个变体,迭代工作。顾名思义,它采用自下而上的方法。这个直觉直截了当:合并所有大小为1的子数组,然后合并所有大小为2的子数组,然后合并所有大小为4的子数组,直到整个数组合并为止。
<强>性能强>
mergesort的两个变体具有相同的运行时间,因为操作完全相同。不同之处在于实施。一个是迭代的,另一个是递归的。我想人们对自己的偏好更容易理解。
关于调用堆栈的大小,没有什么可担心的。对于自上而下的mergesort,调用堆栈不能超过log n,这非常少。避免深度调用堆栈是很好的,如果数据已经排序,这种情况可以在quicksort上发生,但是在mergesort中永远不会发生。