1 概述
- 競賽樹分爲贏者樹和輸者樹,贏者樹更直觀,輸者樹實現更高效。
- 比賽用二叉樹來描述,每個外部節點表示一名選手,每個內部節點表示一場比賽,同一層內部節點代表一輪比賽,可以同時進行。
如果競賽樹是完全二叉樹,則對於n個選手的比賽,最少的比賽場次爲。 - 競賽樹不全是完全二叉樹,但是完全二叉樹可以是比賽的次數最少,競賽樹也成爲選擇樹。
2 贏者樹
2.1 定義
(1)贏者樹:有n個選手的贏者樹是一個完全二叉樹,有n個外部節點和n-1個內部節點,每個內部節點記錄的是該節點比賽的贏者。
分類:最大贏者樹、最小贏者樹(平局的時候左孩子選手獲勝)
優點:當一個選手分數改變時,修改競賽樹比較容易。
2.2 抽象數據類型winnerTree
假設:選手個數一定,初始化後不能增減選手。
選手本身並不是贏者樹的組成部分,內部節點纔是。
template<class T>
class winnerTree
{
public:
virtual ~winnerTree() {}
virtual void initialize(T* thePlayer, int theNumberOfPlayers) = 0;
// create winner tree with thePlayer[1:numberOfPlayers]
virtual int winner() const = 0;
// return index of winner
virtual void rePlay(int thePLayer) = 0;
// replay matches following a change in thePLayer
};
2.3 贏者樹的實現
(1)表示
n名選手,n-1個內部節點分別對應數組player[1: n],tree[1: n-1]
對於任何一個外部節點player[i],其父節點tree[p]由以下公式給出:
其中,、
(2)初始化
從右孩子開始,逐層往上,且每層從左往右依次考察右孩子選手。
(3)類completeWinnerTree
template<class T>
class completeWinnerTree : public winnerTree<T>
{
public:
completeWinnerTree(T* thePlayer, int theNumberOfPlayers)
{
tree = NULL;
initialize(thePlayer, theNumberOfPlayers);
}
~completeWinnerTree() { delete[] tree; }
void initialize(T*, int);
int winner() const
{
return tree[1];
}
int winner(int i) const
{
return (i < numberOfPlayers) ? tree[i] : 0;
}
// return winner of match at node i
void rePlay(int);
void output() const;
private:
int lowExt; // lowest-level external nodes
int offset; // 2^log(n-1) - 1
int* tree; // array for winner tree
int numberOfPlayers;
T* player; // array of players
void play(int, int, int);
};
3 總結
最先適配法求解箱子問題
相鄰適配法求解箱子裝載問題