是否可以避免合并排序中的“除法”步骤?


13

合并排序

因此,合并排序是一种分而治之的算法。在查看上图时,我在考虑是否有可能基本上绕过所有划分步骤。

如果您在原始数组上跳两次时迭代原始数组,则可以在索引i和i + 1处获取元素,然后将它们放入自己的排序数组中。一旦拥有所有这些子数组(如图所示,[[7,14],[3,12],[9,11]和[2,6]),您就可以简单地进行常规合并例程来获取排序数组。

遍历数组并立即生成所需的子数组是否比整体执行除法步骤效率低?


Answers:


29

混淆的产生是由于算法的概念描述与实现之间的差异。

逻辑上将合并排序描述为将数组拆分为较小的数组,然后将它们合并在一起。但是,“拆分数组”并不意味着“在内存中创建一个全新的数组”或类似的东西-它可以在代码中实现为

/*
 * Note: array is now split into  [0..n) and [n..N)
 */

也就是说,没有实际的工作发生,“分裂”纯粹是概念上的。因此,您的建议当然可以工作,但是从逻辑上讲,您仍在“拆分”阵列-您只需要从计算机上进行任何工作即可:-)


4
我个人非常喜欢自下而上的合并排序方式,因为它的实现方式比较简单,可以避免在每个递归级别分配临时缓冲区。而是一次分配一个缓冲区,然后在它们之间进行乒乓球操作。
棘轮怪胎

从计算上来说,这种除法是无操作的...加操作数的建议只是引入了等效于单元素数组合并的方法,并从第二步开始使用合并,这似乎是多余的,因为原始合并同样有效。优化它没有意义。它仅介绍了冗余的概念和逻辑。
luk32

@ratchetfreak:我也喜欢它,但可悲的是它不等同于自上而下(至少我知道的版本)。它将以不同的方式进行合并,基本上将其舍入到下一个2的幂次幂数组长度,我认为这可能会更慢。您是否知道自下而上的版本可以完全相同地合并,而无需付出其他地方的高昂费用?
user541686

@Mehrdad唯一真正的问题是需要合并的小尾巴。在最坏的情况下,这意味着另一遍将合并为length数组的单个项目1<<n+1。虽然我敢肯定您可以调整一下内容,但是太小的尾巴会在较低的通道中合并。
棘轮怪胎

@psmears“您只需要从计算机上进行任何工作就可以了”-因此,我猜想某些递归除法函数(示例图中为7个调用)的n次调用的性能成本基本可以忽略不计?
Jimmy_Rustle

11

我想你的意思是自下而上的实现。在自下而上的实现中,您将从单个单元格元素开始,通过将元素合并到更大的排序列表/数组中来向上移动。只需从中间数组(即一个元素的数组)开始反转上图中的箭头。

另外,您可能希望通过分割数组来优化合并排序,直到它们达到某个恒定大小为止,然后您可以简单地使用例如插入排序对它们进行排序。

否则,无法进行不拆分数组的排序。实际上,合并排序的要点是对子数组进行分割和排序,即分治。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.