勝者樹和敗者樹都是完全二叉樹,是樹形選擇排序的一種變型。每個葉子結點相當於乙個選手,每個中間結點相當於一場比賽,每一層相當於一輪比賽。不同的是,勝者樹的中間結點記錄的是勝者的標號;而敗者樹的中間結點記錄的敗者的標號。
勝者樹與敗者樹可以在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匹馬,所以要用外部...