似乎递归合并排序的除法步骤似乎是不必要的。自下而上的实现方式是将数组拆分为成对的对并直接从那里合并,这似乎总是比递归地拆分和合并更好,因为它会跳过拆分步骤。
是否有理由使用自上而下的合并排序,为什么比自下而上的合并排序更易于实现?
答案 0 :(得分:1)
假设合并排序的是优化版本和基本版本(不是混合版本),则存在一个问题,即数组的大小是否不是2的幂,那么自上而下的分割效果更好,但自上而下不会开始合并直到递归拆分产生两个大小为1的游程,因此在那里没有增益,并且子数组大小的不平衡不会像递归拆分数组并将所有这些索引存储在数组上的开销那样影响整体性能。堆。还有一个缓存局部性的问题:对于自上而下的合并排序,当子数组大小足够小时,合并(输出)的数据仍将保留在缓存中,并可用作下一个合并操作的输入,但与此同时还可以访问合并的数据缓存,以将其刷新到主内存中。
自上而下的递归开销的时间复杂度为O(log2(n)),而自上而下和自下而上的合并排序的总排序时间复杂度为O(n log2(n)),因此为数组大小变大时,自上而下的相对开销会减少,因为大部分时间将花费在合并子数组上。
在我所有的基准测试中,自下而上总是比自上而下快,但是对于大型阵列而言则相对较少。在我的系统(英特尔3770K 3.5 GHz,Windows 7 Pro 64位,Visual Studio 2015)上,对于1600万个64位无符号整数,自下而上大约需要1.5秒,自上而下大约需要1.6秒。
大多数实际库使用自底向上合并排序的一些变体,通常是小型子数组(16到64个元素)的插入排序和自底向上合并排序(例如TimSort)的混合组合。选择与插入排序配合使用的子数组的大小,以使它进行偶数次归并排序,最终将排序后的数据存储在原始数组中。
这使自上而下的合并排序主要是一种学习练习,尤其是在与快速排序同时进行自学习的情况下。