Loading [MathJax]/jax/output/HTML-CSS/jax.js

合併插入排序

Lester Ford, Jr. 以及 Selmer Johnson 把 Howard B. Demuth 的 1957 年博士論文裡面提到的 5 筆資料排序方法進行推廣,最終獲得一個用謹慎的方法試圖減少比較次數的排序方法──合併插入排序 Merge Insertion Sort。 這個排序法的名字是高德納教授(Donald Knuth)在他撰寫的《The Art of Computer Programming》裡面取的。 附帶一提,最近 MIT 教授 Lex Fridman 釋出了一段與 Knuth 的訪談1:https://www.youtube.com/watch?v=2BdBfsXbST8 大家有興趣可以聽聽看。

如何避免大量的天花板

演算法的核心概念是這樣的:如果看到一個長度為 2k1 元素的序列,那麼此時將一個新的元素插入其中,是最不會浪費「資訊」的。因為資訊理論下界 \ceillog2((2k1)+1) 無論有沒有天花板,其數值都是一樣的,得花費恰巧 k 次才能夠找出新元素的落點。

如果長度不到 2k1 的序列怎麼辦?盡量讓這件事情不要發生就好了! 乍看之下很困難啊──但是 Ford-Johnson 盡量做到了,最重要的想法可以透過下面這張圖來傳達:

假設我們能夠經過若干次比較之後,把所有元素的大小關係描述成上面這張圖。其中 xy 代表經過比較以後,我們得出了 x<y 這項結論。 上圖黃色框線內共有 7 個元素,若我們想將紅色元素插入上面長鏈中,此時恰好達到資訊理論下界的 log2(7+1)=3 次。因此可以得到結論是:此時優先將紅色元素插入長鏈、再將左邊的藍色元素插入長鏈。其需要的比較次數至多是 log2(7+1)+log2(7+1)=6 次。相反地,若我們先插入藍色元素,再插入紅色元素,在最壞情形下我們得花費 log2(7+1)+\ceillog2(8+1)=7 次比較才能達到效果。

行文至此,不難發現,如果我們有辦法把輸入資料的大小關係,表達成上圖這種牙刷形狀,再依照最不浪費比較次數的方式進行二分插入,說不定可以得到較佳(比較次數較小)的排序演算法。

合併插入排序的第一步

要怎麼生出牙刷呢? 首先,在分而治之的部分,我們先將資料隨意地兩兩分成一組,並且花費 \floorn/2 次比較。 如果有多出來的元素,就先放在旁邊吧。 接下來,我們可以遞迴針對比較大的那些 \floorn/2 元素進行排序,就可以把它們接成一長串了! 最後是刷毛整理的部分:我們將刷毛由左至右(資料可以命名為 b1,b2,,b\ceiln/2)分成若干組,而每一組的數量都會滿足:把這組資料由右至左依序進行二分插入法,都是最不浪費資訊的。

我們現在來引用 Donald Knuth 《The Art of Computer Programming》裡面提到的分析技巧2

這些組別分起來,會長得像這樣:{b1}{b2,b3}{b4,b5}{b6,b7,b8,b9,b10,b11}…。我們可以令 tk 代表最大的註標使得把跟它分派到同一組的所有元素,依照反過來的順序依序二分插入序列時,最壞情形下每次都恰好需要 k 次比較。即,跟 t0 同一組的資料插入序列恰好需要 0 次比較、跟 t2 同一組的資料插入序列需要 2 次比較、依此類推。

要怎麼找出 tk 的值呢?注意到,當 btk 的筆資料被插入序列的時候,所有註標不超過 tk1 的資料已經被加入序列了。此外,所有註標等於 tk1+1,,tk 的元素都還沒有被加入序列。也就是說,此時序列恰恰好有 2tk1+(tktk11)=tk1+tk1 筆資料!(這個 1 是因為最後一個註標 btk 頭頂上那筆資料不需要被考慮進去,它的資料比所有人都來得大)為了讓資訊不浪費,我們希望 tk1+tk1=2k1。因此得到 tk1+tk=2k 經過一番寒徹骨,不是,經過一翻兩瞪眼以後,不是,總之,經過一直翻一直翻,我們可以得出一個神奇的結論: tk=2k2k1+2k2+(1)k20=(2k+1+(1)k)/3.

有了這個演算法以後,我們就可以利用遞迴方法來分析,這個合併插入排序需要的比較總次數了。我們令 F(n) 表示對 n 筆資料進行 Merge-Insertion Sort 最壞情形下所需要的比較次數。 那麼可以得到遞迴關係:

F(n)=\floorn/2+F(\floorn/2)+G(\ceiln/2)

其中,G(\ceiln/2) 表示著當牙刷刷毛有 \ceiln/2 根的時候(分別是 b1,b2,,b\ceiln/2),要合併成一條單鏈需要的比較次數。藉由 {ti} 的表示法,若 tk1<\ceiln/2tk,我們可以把 G(\ceiln/2) 寫成

G(\ceiln/2)=k1i=1i(titi1)+k(\ceiln/2tk1)=k\ceiln/2(t0+t1++tk1)

wk=t0+t1++tk1=\floor2k+1/3。 現在來證明今天最重要的一個結論:

引理 22

F(n)F(n1)=k 若且唯若 wk<nwk+1

證明

我們可以用數學歸納法。Base Case 很顯然,所以就不寫了。Inductive Case 的部分可以利用 n 的奇偶性分別討論:如果 n 是偶數,那麼 F(n)F(n1)=1+F(n/2)F(n/21),後半部的數值等於 k1 若且唯若 wk1<\floorn/2wk。而由 wk 之定義可知

wk1<n/2wkn 是偶數。)\floor2k/3<n/2\floor2k+1/32\floor2k/3<n2\floor2k+1/32\floor2k/3+1<n2\floor2k+1/3n 是偶數,這很重要。)\floor2k+1/3<n\floor2k+2/3

於是 n 是偶數的時候結論成立。第二種情形,當 n 是奇數的時候,我們可以依樣畫葫蘆:

F(n)F(n1)=G(\ceiln/2)G(\ceil(n1)/2)

然後這個值是 k 若且唯若 tk1<\ceiln/2tk,然後這個等價於 wk<nwk+1,得證。


有了引理 22 以後,我們試圖找出 kn 之間的關係。因為 wk<nwk+1,所以 k 可以寫成 \ceillog234n。於是得到很酷的結論:

F(n)=ni=1\ceillog234inlog2n1.415n+O(log2n)

還記得二分插入法的上界、以及資訊理論下界嗎?我們把它們同步列出來:

A(n)=\ceillogn!nlog2n1.443n+O(log2n)

B(n)=ni=1\ceilloginlog2n0.915n+O(log2n)

不難發現 F(n) 比起二分插入法得到的比較次數 B(n),更接近資訊理論下界 A(n) 了呢!

結論

後話就是,在 1979 年 Manacher3 用了混合方法,把 Hwang-Lin4 的兩序列合併演算法考慮進去並且在某些情形下改良,同時改進了 Ford-Johnson 演算法,並且證明了存在無窮多個 n,其最少比較排序的比較次數比 F(n) 嚴格來得小,該方法贏過 FJ 的最小值是 n=189。然後到了 1985 年 Bui 和 Thanh5 再次修改了 Manacher 演算法,得出在絕大多數的 n 時,FJ 演算法不是最優的。而且也得出了最小反例出現在 n=47(到 2007 年為止,Peczarski6 聲稱 FJ 演算法在 n<47 的時候是最佳解,Peczarski 證明了利用某一類型的分而治之演算法無法在 n46 的時候贏過 FJ 演算法。)

然後 F(n) 其實有封閉形式(Closed Form,俗稱公式解): F(n)=n\ceillog234n+\floor132\floorlog26n+\floor12log26n

最後,大家要多多刷牙喔 ^_<。


合併插入排序法中間的分析,利用到了「如何從排序到一半的東西,利用盡量少比較次數完成排序」的特性。我們是否可以把這個概念推廣一下呢?排序到一半的東西,可以被表示成一個叫做 偏序集(Partial Ordered Set) 的東西。我們能否從偏序集獲得一些排序知識呢?

推薦閱讀

  • 維基百科:https://en.wikipedia.org/wiki/Merge-insertion_sort
  • Ford-Johnson 演算法當年的論文:https://www.jstor.org/stable/pdf/2308750.pdf
1

感謝 a127 的告知與推薦!

2

Donald Knuth, The Art of Computer Programming, Volumn 3, Page 183-187.

3

Glenn K. Manacher, The Ford-Johnson Sorting Algorithm Is Not Optimal, 1979. https://dl.acm.org/doi/pdf/10.1145/322139.322145

5

T. D. Bui and Mai Thanh, Significant improvements to the Ford-Johnson algorithm for sorting, BIT 1985. https://link.springer.com/article/10.1007/BF01934989

4

交大黃光明教授與 S. Lin(我查不到…)當年在貝爾實驗室發表的論文:F. K. Hwang and S. Lin, A Simple Algorithm for Merging Two Disjoint Linearly Ordered Sets, SIAM Journal of Computation, 1972. https://epubs.siam.org/doi/abs/10.1137/0201004

6

Marcin Peczarski, The Ford–Johnson algorithm still unbeaten for less than 47 elements, IPL 2007 February. https://www.sciencedirect.com/science/article/pii/S0020019006002742