定義:
敗者樹是乙個完全二叉樹,非葉子節點記錄失敗者。那麼相對於勝者樹,具有訪存小的優勢。勝者樹勝者拿走後,整條通路(從葉子到根)所有記錄的勝者資訊失效,那麼新加入節點需要從葉子一直遍歷到根,有可能每次都要寫入(更新新的勝者)。而敗者樹,新加入的節點可以利用整條路徑的敗者資訊。
敗者樹構建
構建過程:
① 初始四個陣列,1,2,3,4,內部節點為-1;構建完全後,內部節點記錄陣列編號。
② 陣列4中元素18與父節點比較,父節點為-1,更新為4,退出;等待後面元素更新父節點。
③ 陣列3中元素11與父節點記錄的敗者4(陣列4中元素18)比較,記錄敗者4,勝者3上浮,更新,遇到-1停止上浮,退出。
④ 陣列2中元素6與父節點比較,父節點為-1,更新為2,退出;等等後面元素更新父節點。
⑤ 陣列1中元素7與父節點記錄的敗者2(陣列2中元素6)比較,記錄敗者1,勝者2上浮與父節點記錄的3比較。
⑥ 陣列2(6)與陣列3(11)比較,記錄敗者3,將最終勝者2單獨記錄。
⑦ 至此,敗者樹構建完畢。
敗者樹排序
規定:小於等於為勝利者。
① 勝者為陣列1,拿掉5以後,陣列1彈出乙個元素。
② 陣列1中新元素12與父節點比較(即陣列2中元素6比較),記錄敗者1,勝者2上浮,與陣列3比較,取得勝利。
③ 勝者為陣列2,拿掉6以後,陣列2彈出乙個元素。
④ 陣列2中新元素9與父節點比較(即資料1中元素12比較),記錄敗者1,勝者2上浮,與陣列3比較,取得勝利。
⑤ 勝者為陣列2,拿掉9以後,陣列2彈出乙個元素。
⑥ 陣列2中新元素12與與父節點比較(即陣列1中元素12比較),記錄敗者1,勝者2上浮,與陣列3比較,失敗。
⑦ 勝者為陣列3,拿掉11以後,陣列3彈出乙個元素。
⑧ 陣列3中新元素15與父節點比較後(即陣列4中元素18比較),記錄敗者4,勝者3上浮,與陣列2比較,失敗。
⑨ 勝者為陣列2.
**實現
#ifndef _loser_tree_h_
#define _loser_tree_h_
#include
#include
class player ;
class losertree ;
losertree();
~losertree();
// addplayer takes the ownership of player.
void addplayer(player* player);
bool playnextgame();
element getwinner();
private:
bool buildtree();
void buildimpl(const
int players_slot);
bool is_build_;
std::vector
players_;
std::vector
inner_node_;
};#endif
#include "loser_tree.h"
#include
#define loser_tree_sentinel -1
#define loser_tree_max_value int_max
losertree::losertree()
losertree::~losertree()
}void losertree::addplayer(player* player)
}bool losertree::buildtree()
// init inner node.
inner_node_.reserve(players_.size());
for (size_t i = 0; i < players_.size(); ++i)
for (int i = players_.size() - 1; i >= 0; --i)
return
true;
}void losertree::buildimpl(const
int player_slot)
// winner becomes loser, record loser.
if (players_[winner_slot]->value() >
players_[parent_slot]->value())
} // update winner.
inner_node_[0] = winner_slot;
}bool losertree::playnextgame()
if (inner_node_.empty())
int winner_slot = inner_node_[0];
if (winner_slot == loser_tree_sentinel ||
players_[winner_slot]->value() == loser_tree_max_value)
players_[winner_slot]->next();
buildimpl(winner_slot);
return players_[inner_node_[0]]->value() != loser_tree_max_value;
}losertree::element losertree::getwinner()
player::player(const
std::vector
& container)
: container_(container)
player::~player()
void player::next()
int player::value() else
}
#include "loser_tree.h"
#include
#include
using
namespace
std;
int main()
return
0;}
敗者樹與外部多路歸併排序
在處理大資料量的排序時,由於資料無法全部載入到記憶體,內部排序無法對整個資料集進行排序,需要到外部排序。外部排序有一些特點,跟記憶體容量和讀寫檔案有關 1.讀寫檔案,需要考慮 io 時間 2.從無序到逐步有序的過程中,需要多個中間檔案外部排序有多種,常見的歸併排序的如下 輸入為大檔案 f 排序過程分...
7 7 3 多路平衡歸併與敗者樹
歸併趟數s logm r 向下取整 從而增加歸併路數m可以減少歸併趟數s,進而減少訪問外存的次數 i o次數 然而,當增加歸併路數m時,內部歸併時間將增加。做內部歸併時,在m個元素中選擇關鍵字最小的記錄需要比較m 1次。每趟歸併n個元素最多需要作 n 1 m 1 次比較,s趟歸併總共需要的比較次數為...
外部排序 勝者樹與敗者樹
參考 引子 前面講到的google面試題 賽馬問題 我一直在想,會不會有一種演算法能講得更清楚,更明白呢。後來我發現賽馬問題和外部排序之歸併排序很相似。賽馬問題中由於賽道只能一次賽5匹馬,就好比我們要對25匹馬進行排序,但是發現計算機記憶體不夠 賽道是賽5匹馬的 最多同時只能排序5匹馬,所以要用外部...