勝者樹與敗者樹(二)

2021-07-10 19:37:35 字數 3145 閱讀 8978

勝者樹和敗者樹都是完全二叉樹,是樹形選擇排序的一種變型。每個葉子結點相當於乙個選手,每個中間結點相當於一場比賽,每一層相當於一輪比賽。不同的是,勝者樹的中間結點記錄的是勝者的標號;而敗者樹的中間結點記錄的敗者的標號。

勝者樹與敗者樹可以在log(n)的時間內找到最值。任何乙個葉子結點的值改變後,利用中間結點的資訊,還是能夠快速地找到最值。在k路歸併排序中經常用到。

勝者樹的乙個優點是,如果乙個選手的值改變了,可以很容易地修改這棵勝者樹。只需要沿著從該結點到根結點的路徑修改這棵二叉樹,而不必改變其他比賽的結果。下面是選擇乙個最小的數字為最勝利者(見圖1所示),第一次把各個陣列裡面的第乙個元素都放進去,這是根據勝利樹的規則兩兩比較,得到最小的值,第一次弄完之後,就得出1數字是勝利的,也就是1是最小的。在下一次輸出第二小的數字時候,只需要把1所在的陣列裡面的元素加進去,然後從葉子節點到根節點一直比較得出第二小的值,這樣就減少了很多次無用的比較(見圖2所示)。

問題:有20個有序陣列,每個陣列有500個uint變數,降序排序。要求從這10000個元素中選出最大的500個。

有人可能會有疑問,就是如果給定的是奇數個陣列,那麼這個勝者樹是不是不能用了呢,其實是可以的。我們大不了可以加乙個陣列,把陣列的個數湊成偶數。這個新加的陣列中的所有元素置為極大值或者極小值。這樣,這些元素雖然被構建到勝者樹中,但是他們因為是極大或者極小的,所以不被納入勝者樹的計算結果中。所以不會產生影響。這樣是比較浪費點空間。如果覺得不想浪費這麼多的空間,其實還有個辦法,那就是在構建勝者樹的時候考慮奇偶。如果x是偶數,那麼就分配2*x的空間,把 x-2x-1的元素都賦值。而第0個空間是不用的。第乙個空間儲存勝者樹的根。如果是奇數的情況,算一下要用的節點數。2*(x + 1) - 1個,所以直接分配 2 *( x + 1) 個節點,把最後乙個節點的值置為最大或者最小。下面給出程式**:

[cpp]view plain

#include

#include

#include

#include

using

namespace

std;  

#define inf 100000

#define n 10

typedef

struct

nodenode;  

intcom(

const

void

*a, 

const

void

*b)else

if(*(

int*)a 

int*)b)     

return

0;    

}    

void

adjusttreeforfirst(node *temparray, 

intlen)  else

}  i /= 2;  

}  }  

void

get_data(

int**a, 

introw, 

intcol, 

intlen)   

for(j = 0; j 

}  cout <

<

for(i = 0; i 

delete

result;  

delete

temp;  

}  int

main()     

//初始化陣列   

cout <

<

srand( time(null) );     

for(i = 0; i 

}    

//排序   

for(i = 0; i 

get_data(a, row, col, 40);  

return

0;  

}  

敗者樹:

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

fig. 1

fig. 1是一棵敗者樹。規定數大者敗。

b3 pk b4,b3勝b4負,內部結點ls[4]的值為4;

b3 pk b0,b3勝b0負,內部結點ls[2]的值為0;

b1 pk b2,b1勝b2負,內部結點ls[3]的值為2;

b3 pk b1,b3勝b1負,內部結點ls[1]的值為1;

在根結點ls[1]上又加了乙個結點ls[0]=3,記錄的最後的勝者。

敗者樹重構過程如下:

fig. 2

fig. 2是當b3變為13時,敗者樹的重構圖。

注意,敗者樹的重構跟勝者樹是不一樣的,敗者樹的重構只需要與其父結點比較。對照fig. 1來看,b3與結點ls[4]的原值比較,ls[4]中存放的原值是結點4,即b3與b4比較,b3負b4勝,則修改ls[4]的值為結點3。同理,以此類推,沿著根結點不斷比賽,直至結束。

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

fig. 3

fig. 3是一棵敗者樹。規定數大者敗。

b3 pk b4,b3勝b4負,內部結點ls[4]的值為4;

b3 pk b0,b3勝b0負,內部結點ls[2]的值為0;

b1 pk b2,b1勝b2負,內部結點ls[3]的值為2;

b3 pk b1,b3勝b1負,內部結點ls[1]的值為1;

在根結點ls[1]上又加了乙個結點ls[0]=3,記錄的最後的勝者。

敗者樹重構過程如下:

fig. 4

fig. 4是當b3變為13時,敗者樹的重構圖。

注意,敗者樹的重構跟勝者樹是不一樣的,敗者樹的重構只需要與其父結點比較。對照fig. 3來看,b3與結點ls[4]的原值比較,ls[4]中存放的原值是結點4,即b3與b4比較,b3負b4勝,則修改ls[4]的值為結點3。同理,以此類推,沿著根結點不斷比賽,直至結束。

勝者樹與敗者樹

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

勝者樹與敗者樹

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

外部排序 勝者樹與敗者樹

參考 引子 前面講到的google面試題 賽馬問題 我一直在想,會不會有一種演算法能講得更清楚,更明白呢。後來我發現賽馬問題和外部排序之歸併排序很相似。賽馬問題中由於賽道只能一次賽5匹馬,就好比我們要對25匹馬進行排序,但是發現計算機記憶體不夠 賽道是賽5匹馬的 最多同時只能排序5匹馬,所以要用外部...