12勝者樹和敗者樹

2021-07-03 05:50:52 字數 3465 閱讀 1336

一:勝者樹(

問題描述:給出乙個長度是n的陣列,現在要找出最小的兩個元素,最少要多少次比較。

分析: 如果找出1個最小的,比較次數無疑是n-1;如果用選擇排序,再取選擇第二個最小的又得比較n-2次。這種尋找的辦法其實是可以優化

的,在第一次尋找最小元素過程中,其實我們已經比較了很多元素了,那麼為什麼不利用前面比較的結果來尋找第二個最小的呢。

這用到勝者樹的資料結構,這樣就可以再logn就可以找到了第二小的元素。勝者樹在求陣列最大值,次大值得時候,有用武之地。

勝者樹排序,屬於選擇排序的一種。直接選擇排序之所以不夠高效就是因為沒有把前一趟比較的結果保留下來,每次都有很多重複的比較。勝者樹排序就是要克服這一缺點。它的基本思想與體育淘汰賽類似,首先取得n個元素的關鍵字

,進行兩兩比較,得到 n/2 個比較的優勝者,將其作為第一次比較的結果保留下來,然後對這些元素再進行關鍵值的兩兩比較,…,如此重複,直到選出乙個關鍵字最小的物件為止。

下面舉個例子,假設arr = ,我們首先需要建立一棵完全二叉樹,陣列arr的元素分布在葉子節點上,內部節點儲存了比賽的結果。如下圖所示的完全二叉樹:

完全二叉樹的性質就是:內部節點數=葉子節點數-1。所以,該勝者樹的資料結構可以這樣儲存:

根據上面的示意圖,其實我們還需要乙個變數來儲存勝者的索引。我們再來畫一下圖,逗號後面記錄了勝者的索引:

於是,第一次建樹,就成上面這樣了,我們可以輕鬆通過根節點得到最後的勝者(最小節點),並且同時知道勝者的索引號。下次在搜尋最小值的時候,我們需要將剛才勝者值替換為最大值,然後沿著紅色的線比較一遍就行了,這次只需要比較三次就行了(logn),請看下圖。

然後,一直進行這個過程中就可以完成對陣列的排序,排序的時間複雜度。

從這個演示可以看出這個演算法

真正吸引我們的地方就是當決出乙個勝者後,要取得下乙個勝者的比較只限於從根到剛才選出的外結點這一條路徑上。可以看出除第一次比較需要n-1次外,此後選出次小,再次小......的比較都是log n次,故其複雜度為o(nlogn)。但是對於有n個待排元素,錦標賽演算法需要至少2n-1個結點來存放勝者樹。故這是乙個拿

空間換時間的演算法。

**如下:

typedef  struct

treenode;

treenode *buildwinnertree(int *set, int setsize)

for(i = setsize-1; i < treesize;i++)

int p,l,r;

p =(treesize-2)/2;

while(p >= 0)

else

p--; }

return tree; }

void  printkth(treenode *tree, int kth)

} void  adjusttree(treenode *tree, int index)

else

if(p > 0)p = (p-1)/2;

else break; }

}二:敗者樹

敗者樹也是乙個完全二叉樹,一顆敗者樹中的結點有葉子節點和內部結點。其中葉子結點就是原陣列,即需要抽取最小值的陣列。內部結點代表失敗者。在實現敗者樹的時候,分別用兩個陣列表示:ls陣列表示內部結點,從0到k-1.b陣列表示葉子節點,也就是原陣列,從0到k-1.

敗者樹中用父結點記錄其左右子結點進行比賽的敗者,而讓勝者參加下一輪的比賽。敗者樹的根結點記錄的是敗者,需要加乙個結點來記錄整個比賽的勝利者。採用敗者樹可以簡化重構的過程。如下圖:

在上圖中,方框表示葉子結點,圓圈表示內部結點。可以看見內部結點為ls[0..4],葉子節點為b[0..4]。上圖的敗者樹,構造過程如下(小者為勝):

a:b3 vs b4,b3

勝b4負,內部結點ls[4]的值為4,表示b4為敗者;勝者b3繼續參與競爭。

b:b3 vsb0,b3

勝b0負,內部結點ls[2]的值為0,表示b0為敗者;勝者b3繼續參與競爭。

c:b1 vs b2,b1

勝b2負,內部結點ls[3]的值為2,表示b2為敗者;勝者b1繼續參與競爭。

d:b3 vs b1,b3勝b1負,內部結點ls[1]的值為1,表示b1為敗者;勝者b3為最終冠軍,用ls[0]=3,記錄的最後的勝者索引。

敗者樹重構過程如下:

將新進入選擇樹的結點與其父結點進行比賽:將敗者存放在父結點中;而勝者再與上一級的父結點比較。比賽沿著到根結點的路徑不斷進行,直到ls[1]處。把敗者存放在結點ls[1]中,勝者存放在ls[0]中。如下圖:

當b3變為13時,敗者樹的重構過程如下:

a:b3 vs b[ls[4]],也就是b3 vsb4,b4

勝,繼續參加下面的競爭,ls[4]=3記錄敗者。

b:b4vs b[ls[2]],也就是b4 vs b0, b0

勝,繼續參加下面的競爭,ls[2]=4記錄敗者。

c:b0vs b[ls[1]],也就是b0 vs b1, b1勝,b1為最終冠軍,所以ls[0]=1記錄冠軍,ls[1]=0記錄敗者。

**如下:

void  adjust(int s)

t=t/2; }

ls[0]=s; }

void  createlosertree()

敗者樹簡化了重構。敗者樹的重構只是與該結點的父結點的記錄有關,而勝者樹的重構還與該結點的兄弟結點有關。所以敗者樹在外排序的k路平衡歸併中使用。利用敗者樹進行外部排序的**如下:

void k_merge()  

for(i = 0; i < k; ++i) 

}  createlosertree();

int q;

while(b[ls[0]]!=max)

for(i = 0; i < k; ++i)   

delete farray; 

fclose(fout);  }

勝者樹與敗者樹

概念介紹 勝者樹和敗者樹都是完全二叉樹,是樹形選擇排序的一種變型。每個葉子結點相當於乙個選手,每個中間結點相當於一場比賽,每一層相當於一輪比賽。不同的是,勝者樹的中間結點記錄的是勝者的標號 而敗者樹的中間結點記錄的敗者的標號。勝者樹與敗者樹可以在log n 的時間內找到最值。任何乙個葉子結點的值改變...

勝者樹與敗者樹

勝者樹與敗者樹 勝者樹和敗者樹都是完全二叉樹,是樹形選擇排序的一種變型。每個葉子結點相當於乙個選手,每個中間結點相當於一場比賽,每一層相當於一輪比賽。不同的是,勝者樹的中間結點記錄的是勝者的標號 而敗者樹的中間結點記錄的敗者的標號。勝者樹與敗者樹可以在log n 的時間內找到最值。任何乙個葉子結點的...

勝者樹與敗者樹(二)

勝者樹和敗者樹都是完全二叉樹,是樹形選擇排序的一種變型。每個葉子結點相當於乙個選手,每個中間結點相當於一場比賽,每一層相當於一輪比賽。不同的是,勝者樹的中間結點記錄的是勝者的標號 而敗者樹的中間結點記錄的敗者的標號。勝者樹與敗者樹可以在log n 的時間內找到最值。任何乙個葉子結點的值改變後,利用中...