22功能之败者树的解析与代码实现
1 败者树的构建过程
2 解析上图
败者树由内部节点与叶子节点组成。
1)内部节点指除了叶子节点与ls[0];
2)叶子节点就是数据节点;
若有K个数据,则叶子节点为K,内部节点为K-1。但是在代码实现过程中,需要有一个最小值与存放最小值下标的地方,而最小值放在叶子节点;最小值下标存放在ls[0]。故长度定义数据节点的数组为K+1;内部节点的长度为K。
Q1:上面为何数据节点要使用最小值INT_MIN?
因为方便在第一次调整的时候建立好败者树。
Q2:为何loserTree[2]下面的数据点有时是data[0],有时是data[n-1]?
因为叶子节点与内部节点建立关系是我们自己实现的,即
t=(s+Len)/2;这样我们调整败者树传进参数s时,就会规定你是data[0]还是data[n-1];总之一句话,因为叶子节点和内部节点的关系是我们自己定义的,数据怎么连接看连接的公式。不懂可以看下面的代码。
3 代码实现
int ls[K]; //ls[0]存最小值下标,1-K-1存内部节点,即每次的亚军
int b[k+1]; //ls[K]存最小值,0-K-1存数据
void CreateLoser() {
//1 初始化数据节点的最小值
b[m_file] = MIN;
//2 初始化内部节点记录的下标
for (int i = 0; i < m_file; i++) {
ls[i] = m_file;
}
//3 调整败者树
for (int i = m_file - 1; i >= 0; i--) {
Adjust(i);
}
}
//调整败者树 s一开始代表当前节点,实际是一直指向胜利者,即数据最小的值(与用于初始化的最小值MIN不一样)
void Adjust(int s) {
int tmp;
int t = (s + m_file) / (2); //叶子节点与内部节点建立关系,t代表当前节点s的父节点
while (t > 0) { //t=0,即父节点是ls[0]节点时,证明该次排序调整结束,已经找到最小值了嘛
if (b[s] > b[ls[t]]) { //新入树节点大于上一次的父节点,父节点记录新的失败者
tmp = s;
s = ls[t]; //s永远指向胜利者,即最小值
ls[t] = tmp; //父节点保存新的失败者
}
t = t / 2; //沿根节点上比较
}
ls[0] = s;
}