为什么MergeSort的偶数分裂“更快”?

时间:2011-05-25 12:41:22

标签: algorithm performance big-o mergesort

  

MergeSort是一种分而治之的算法,它将输入分成几个部分并递归地求解这些部分。

     

......分割功能有几种方法。一种方法是拆分中间。这种方法有一些很好的属性,但是,我们将专注于一个更快一点的方法:奇偶分裂。我们的想法是将每个偶数位置元素放在一个列表中,将每个奇数位置放在另一个列表中。

这直接来自我的讲义。为什么奇偶分裂的速度比阵列中间快?

我猜测它与传入MergeSort的列表有关,并且质量已经已经排序,但我不完全确定。

有人可以对此有所了解吗?

编辑:我尝试在Python中运行以下内容......

global K
K = []
for i in range (1, 100000):
    K.append(i)


def testMergeSort():
"""
testMergeSort shows the proper functionality for the
Merge Sort Algorithm implemented above.
"""

t = Timer("mergeSort([K])", "from __main__ import *")
print(t.timeit(1000000))

p = Timer("mergeSort2([K])", "from __main__ import *")
print(p.timeit(1000000))

(MergeSort是奇数MergeSort,MergeSort2将中心分开)

结果是:

  
    
      

0.771506746608

             

0.843161219237

    
  

3 个答案:

答案 0 :(得分:1)

我可以看到它可能更好,因为将它与替代元素分开意味着您不必知道输入的开始时间 - 您只需将元素放入交替列表中直到您跑了。

如果您仔细考虑更好的并行处理,那么在完成第一个列表的迭代之前,您可能会开始拆分结果列表。

我应该补充一点,我不是这些问题的专家,他们只是想到的事情......

答案 1 :(得分:1)

输入列表越接近已排序,运行时越低(这是因为如果所有值都已正确,merge过程不需要move任何值它只是执行 O n )比较。由于MergeSort在分割的每一半上递归调用自身,因此需要选择增加的split函数列表生成的一半的可能性是按排序顺序排列的。如果列表主要排序,偶数奇数拆分将比分割中间更好。例如,

MergeSort([2, 1, 4, 3, 5, 7])

会导致

Merge(MergeSort([2, 1, 4]), MergeSort([3, 5, 7]))

如果我们拆分中间(注意两个子列表都有排序错误),而如果我们做了偶数 - 奇数拆分我们会得到

Merge(MergeSort([2, 4, 5]), MergeSort([1, 3, 7]))

导致两个已经排序的列表(以及对MergeSort的后续调用的最佳情况)。但是,在不了解输入列表的情况下,分割函数的选择不应该渐近地影响运行时。

答案 2 :(得分:0)

我怀疑你的实验中有噪音。 :)其中一些可能来自比较和交换实际上没有移动列表中的任何元素,这避免了缓存失效等。

无论如何,这里有一个关于此的聊天:https://cstheory.stackexchange.com/questions/6732/why-is-an-even-odd-split-faster-for-mergesort/6764#6764(是的,我确实在那里发布了类似的答案(完全披露))

相关的维基百科文章指出mergesort是O(n log(n))而Odd-Even Merge Sort是O(n log(n)^ 2)。 Odd-Even肯定是“慢”,但排序网络是静态的,所以你总是知道你将要执行什么操作(查看维基百科条目中的图形)注意算法如何保持平行直到最后。

当合并排序最终合并2个列表时,Odd-Even合并排序的8元素排序网络的最后比较仍然是独立的。