繁体   English   中英

Mergesort - 自上而下快于自上而下吗?

[英]Mergesort - Is Bottom-Up faster than Top-Down?

我一直在阅读Sedgewick和Wayne的“Algorithms,4th Ed”,并且我一直在实现JavaScript中讨论的算法。

我最近采用了书中提供的mergesort示例来比较自上而下和自下而上的方法......但我发现自下而上的运行速度更快(我认为)。 在我的博客上查看我的分析。 - http://www.akawebdesign.com/2012/04/13/javascript-mergesort-top-down-vs-bottom-up/

我还没有找到任何讨论说一个mergesort方法应该比另一个快。 我的实施(或分析)是否存在缺陷?

注意:我的分析测量算法的迭代循环,而不是严格的数组比较/移动。 也许这有缺陷或无关紧要?

编辑: 我的分析实际上没有时间速度,所以我关于它运行“更快”的声明有点误导。 我通过递归方法(自上而下)和for循环(自下而上)跟踪“迭代” - 并且自下而上似乎使用更少的迭代。

我还没有找到任何讨论说一个mergesort方法应该比另一个快。

自上而下和自上而下的合并类别以及其他变体在90年代进行了很好的研究。 简而言之,如果您将成本测量为单个密钥的比较次数,则最佳成本相同(〜(n lg n)/ 2),自上而下的最差成本低于或等于最差成本自下而上的情况(但两者都是n n n)和自上而下的平均成本低于或等于自下而上的平均情况(但都是〜n lg n),其中“lg n”是二进制对数。 差异源于线性项。 当然,如果n = 2 ^ p,则两个变体实际上完全相同。 这意味着,从比较的角度来看,自上而下总是好于自下而上。 此外,已经证明自上而下合并排序的“半”分裂策略是最优的。 研究论文来自Flajolet,Golin,Panny,Prodinger,Chen,Hwang和Sedgewick。

以下是我在Erlang中出版的“纯功能程序设计与分析 (英国大学出版物)”一书中提到的内容:

tms([X|T=[_|U]]) -> cutr([X],T,U);
tms(T)           -> T.

cutr(S,[Y|T],[_,_|U]) -> cutr([Y|S],T,U);
cutr(S,    T,      U) -> mrg(tms(S),tms(T)).

mrg(     [],    T)            -> T;
mrg(      S,   [])            -> S;
mrg(S=[X|_],[Y|T]) when X > Y -> [Y|mrg(S,T)];
mrg(  [X|S],    T)            -> [X|mrg(S,T)].

请注意,这不是一个稳定的排序。 此外,在Erlang(和OCaml)中,如果要节省内存,则需要在模式中使用别名 (ALIAS = ...)。 这里的技巧是在不知道其长度的情况下找到列表的中间部分。 这是由cutr / 3完成的,它处理两个指向输入列表的指针:一个递增一个而另一个递增两个,所以当第二个到达结尾时,第一个指向中间。 (我是从Olivier Danvy的一篇论文中学到的。)这样,你不需要跟踪长度,也不需要复制列表后半部分的单元格,所以你只需要(1/2) )n lg n额外空间,相对于n lg n。 这不是众所周知的。

人们常说自下而上的变体更适合函数式语言或链表(Knuth,Panny,Prodinger),但我不认为这是真的。

由于缺乏关于合并类型的讨论,我对你感到困惑,所以我做了自己的研究并写了一篇关于它的大篇章。 我目前正在准备一个新版本,其中有更多关于合并类型的材料。

顺便说一下,还有其他变种:队列合并排序和在线合并排序(我在书中讨论后者)。

[编辑:由于成本的衡量标准是比较次数,因此选择数组与链表之间没有区别。 当然,如果您使用链接列表实现自上而下的变体,您必须聪明,因为您不一定知道键的数量,但每次都需要遍历至少一半的键,并且重新分配,总共(1/2)n lg n个细胞(如果你聪明的话)。 与链接列表的自下而上合并排序实际上需要更多额外的内存,n lg n + n个单元格。 因此,即使使用链接列表,自上而下的变体也是最佳选择。 就程序的长度而言,您的里程可能会有所不同,但在功能语言中,如果不需要稳定性,自上而下的合并排序可以比自下而上更短。 有些论文讨论了合并排序的实现问题,例如就地(您需要数组)或稳定性等。例如,Katajainen和Larsson Traff(1997)对Mergesort 程序的细致分析

我在2012年8月版本课程的课程论坛上提出了同样的问题。 普林斯顿教授Kevin Wayne回答说,在很多情况下,递归比迭代更快,因为缓存提高了性能。

所以我当时得到的简短答案是,由于缓存原因,自顶向下合并排序将比自下而上合并排序更快。

请注意,该课程是用Java编程语言(而不是Javascript)教授的。

如果越快意味着更少的“迭代”,那么是。 如果你想知道执行时间可能。

原因是这些21,513次迭代中的一些迭代比22,527次迭代更多。

从查看源代码来看,图表中的某些叶节点似乎不是单独排序,导致合并和排序更少,但需要更长的时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM