簡體   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