用敗者樹優化K路歸併排序

2021-06-14 04:48:11 字數 2767 閱讀 9046

圖9.16給出的歸併過程屬於2路平衡歸併。做k路平衡歸併(k-way balanced merging)時,如果有m個初始歸併段,則相應的歸併樹有[logkm]+1層,南非要歸併[logkm]趟。

做內部歸併時,在k個物件中選擇最小者,需要順序比較k-1次。每趟歸併u個物件需要做(u-1)*(k-1)次比較,s趟歸併總共需要的比較次數為:

s*(u-1)*(k-1)=[logkm]*(u-1)*(k-1)

=[log2m]*(u-1)*(k-1)/[log2k]

圖9.18  對36個初始歸併段做6路歸併過程

其中的[log2m]*(u-1)在初始歸併段個數 m與物件個數 u一定時是常數,而(k-1)/[log2k]在k增大時趨於無窮大。因此,增大歸併路數k,會使得內部歸併的時間 增大。

下面介紹一種使用「敗者樹」從h個歸併段中選最小者的方法。對於較大的k(k≥ 6),可大大減少查詢下乙個排序碼最小的物件時的比較次數。

利用敗者樹,在k個物件中選擇最小者,只需要o([log2k])次排序碼比較,這時有:

s*(u-1)*[log2k]=[logkm]*(u-1)*[log2k]

=[log2m]*(u-1)*[log2k]/[log2k]=[log2m]*(u-1)

這樣,排序碼比較次數與k無關,總的內部歸併時間不會隨k的增大而增大。因此, 只要記憶體空間允許,增大歸併路數k,將有效地減少歸併樹高度,從而減少讀寫磁碟次數 d,提高外排序的速度。

敗者樹實際上是一棵完全二叉樹。其中每個葉結點存放各歸併段在歸併過程中當前 參加比較的物件,每個非葉結點記憶它兩個子女結點中物件排序碼小的結點(即敗者)。 因此,根結點中記憶樹中當前物件排序碼最小的結點。為敘述簡單起見,以後把排序碼最 小的物件稱為最小物件。設有5個初始歸併段,它們中各物件的排序碼分別是:                     

runo:{ 17, 21,

其中,~k4是各歸併段run[0]~run[4]在歸併過程中的當前物件的排序碼,各非葉結點ls1~ls4。記憶兩個子女結點中(排序碼)小的物件所在歸併段號人。記憶最小物件所在歸併段號。

在ls0中記憶的是當前找到的最小物件所在歸併段號i,根據該段號可取出這個物件,將它送人結果歸併段,再取該歸併段的下乙個物件,將其排序碼送人ki,然後從該葉結點到根結點,自下而上沿子女一雙親路徑進行比較和調整,使下乙個具次小排序碼的物件所在的歸併段號調整到冠軍位置。將最小物件05送人結果歸併段後,該歸併段下乙個物件的排序碼44替補l來,送人k1。k1與其雙親人。中所記憶的上次的敗者k2中的排序碼進行比較,k1是敗者,其歸併段號1記人雙親 ls3,勝者 k2繼續與更上一層雙親ls1中所記憶的敗者k4進行排序碼比較,k4仍是敗者,勝者k2的歸併段號進人冠軍位置ls0。

圖9.19   利用敗者樹選最小物件 

敗者樹高度為[log2k],在每次調整,找下乙個具有最小排序碼物件時,最多做 [log2k] 次排序碼比較。

在實現利用敗者樹進行多路平衡歸井演算法時,把敗者樹的葉結點和非叫結點分開定 義。敗者樹的葉結點 key[k]有k+l個,key[0]~ key[k-1」存放各歸併段當前參加歸併 的物件的排序碼,key[k]是輔助工作單元,在初始建立敗者樹時使用,存放乙個最小的在各歸併段中不可能出現的排序碼:-maxnum。敗者樹的非葉結點loser「k-l]有k個. 其中loser[l]~loser[k一1]川存放各次比較的敗者的歸併段號,loser[0」中是最後勝者所在 的歸併段號。另外還有乙個物件陣列r[k],存放各歸併段當前參加歸井的物件。 在記憶體中應為每乙個歸併段分配乙個輸人緩衝區,其大小應能容納乙個頁塊的物件, 編號與歸併段號一致。每個輸人緩衝區應有乙個指標,指示當前參加歸併的物件。

初始時指向緩衝區第乙個物件。每當乙個物件i被選出並送人輸出緩衝區後,inputrecord(i) 操作修改該物件所在輸入緩衝區的指標,指向下乙個參加歸井的物件,並將這個物件讀人 r[i〕,其排序碼送人 key[i」。當該緩衝區指標指到塊尾,表明緩衝區中物件已處理完,此時應從相應歸併段讀人下乙個頁塊,並將緩衝區指標指到第乙個物件。

在記憶體中還應設立乙個輸出緩衝區,其大小相當於乙個頁塊大小。它也有乙個緩衝 區指標,指示當前可存放結果物件的位置,初始時指向緩衝區第乙個物件位置。每當乙個物件i被選出,就執行outputrecord(i)操作,將物件接輸出緩衝區指標所指位置存放到輸出緩衝區中,然後修改緩衝區指標,指到下乙個存放位置。當輸出緩衝區指標指到塊尾,表明緩衝區已滿,應將緩衝區中全部物件輸出到結果歸併段,再將緩衝區指標指到第乙個物件位置。

k 路平衡歸併排序演算法

void kwaymerge ( element *r )

for ( i = 0; i < k; i++) loser[i] = k; 

key[k] = -maxnum;            //初始化

for ( i = k-1; i; i-- )            //調整形成敗者樹

adjust ( key, loser, k, i ); 

while ( key[loser[0]] != maxnum ) 

output end of run marker;   //輸出段結束標誌

delete [ ] r;  delete [ ] key;  delete [ ] loser;

}自某葉結點key[q]到敗者樹根結點的調整演算法

void adjust ( int key[ ]; int loser[ ]; const int k;const int q )     //q與loser[t]交換

loser[0] = q; }

歸併路數 k 的選擇不是越大越好。歸併路數 k增大時,相應需增加輸入緩衝區個數。如果可供使用的記憶體空間不變,勢必要減少每個輸入緩衝區的容量,使內外存交換資料的次數增大。

Python實現基於敗者樹的K路歸併排序

import random import os,sys 隨機生成不大於max的長度位n的列表 def genlist n,max result for i in range n print result return result 從給定的列表中獲取k個有序列表分組 def splitsortedl...

k路歸併排序

題目 給定k個已序鍊錶,要求盡可能快的將這k個鍊錶合併為乙個有序鍊錶。方案1 將這k個鍊錶標號為1,2,k,對於這k個鍊錶,我們首先合併鍊錶1和鍊錶2,得到乙個有序的鍊錶l12,然後將l12和鍊錶3進行合併.直到k個鍊錶均合併完成,最終便能夠得到有序的鍊錶l1k,即為這k個鍊錶合併後的有序鍊錶。對於...

敗者樹與外部多路歸併排序

在處理大資料量的排序時,由於資料無法全部載入到記憶體,內部排序無法對整個資料集進行排序,需要到外部排序。外部排序有一些特點,跟記憶體容量和讀寫檔案有關 1.讀寫檔案,需要考慮 io 時間 2.從無序到逐步有序的過程中,需要多個中間檔案外部排序有多種,常見的歸併排序的如下 輸入為大檔案 f 排序過程分...