//败者树示例与解析,败者树即是多个数据从二叉树的叶子节点出发,
//逐次比较,败者滞留子结点,胜者上升父节点,最后最终ls【0】为最终胜者。也可以说是多路归并算法
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
#define LEN 5//败者树容量,多路归并数目
#define MIN -1//所有数据的可能最小值
int ls[LEN+1];
//败者树,ls[0]存放胜者,其余存放败者,实际上用到的只有前面len个点,
//树建成后,每个顶点分别对应一路归并序列(链表)
int buf[LEN+1];
//存放多路归并的头元素值,多出来的一位放MIN,这一位用于建树时的比较
void adjust(int s,int *buf){
//s会一直指向buf表中比较过程中的胜者(这里是较小值),
//而败者(在buf的下标)则被记录在ls【t】节点
int t=(s+LEN)/2;
//目前s指向的节点的父节点为t;如当s为0时,0路数据是挂在下标为2的败者树节点下充当叶节点的;
//当s为1或者2时,挂在下标为3的败者树节点下充当子节点。
//由于len为5,所以败者树只有五个节点,拥有数据叶节点的败者树节点则有2,3,4
while(t>0)
{//如果父节点不是ls【0】,则继续比较上升
if(buf[s]>buf[ls[t]]){//如果当前节点s不小于等于父节点,则败,滞留这一层
//下面就是交换ls【t】和s的值
ls[t]^=s;//交换ls[t]和s
s^=ls[t];//s记录胜者
ls[t]^=s;//父节点记录败者
}
t/=2;//得到s的上一个父节点,下一轮继续比较
}
ls[0]=s;//最终的胜者记录于ls[0]
}
void build(int *buf){
buf[LEN]=MIN;//最后一位放MIN,用于建树比较
for(int i=0;i<LEN+1;++i)
ls[i]=LEN;//所有败者树初始化为MIN的下标,这样不会让数据的下标升到不符合它的高度
for(int i=0;i<LEN;++i)//这里是建树,让数据的下标依次上升到相应的高度
adjust(i,buf);
}
int main()
{
//初始buf
int tmp[5]={18,21,16,11,19};
memcpy(buf,tmp,LEN*sizeof(int));
build(buf);
/*
建树完成后:
ls:败者树(注意这里0是1父节点,1是2和3的父节点,所以跟1比较完永远是最小的)
3 2 0 1 4 5
buf:数据存放
18 21 16 11 19 -1
*/
cout<<buf[ls[0]]<<endl;//输出11
//取出11后,buf[3]=17
int tmp1[5]={18,21,16,17,19};
memcpy(buf,tmp1,LEN*sizeof(int));
adjust(3,buf);
cout<<buf[ls[0]]<<endl;//输出16
return 0;
}