特点:败者树每一趟,两节点比较,失败的放在父节点处,胜利者继续跟父节点的父节点比较,相当于拿最小的节点去与根节点交换。
优点:从叶子处新加入一个有结构的败者树,只需要Log2 k次比较即完成了下一轮的数据。
下面代码是一个简单实例,需要将a[0],a[1],a[2],a[3],三行有序列进行归并输出,mark[4]用于标记行数据是否已经读完。
#include <iostream>
#define MAXKEY 10000000
using namespace std;
int k = 4;
int a[4][5] = {1,3,5,7,9,
2,4,6,8,10,
11,13,15,17,19,
12,14,16,18,20};
int mark[4] = {0};
// 获取第i行的下一个数据
int getnext(int i)
{
if(mark[i] == 5)
return MAXKEY;
else
return a[i][mark[i]++];
}
// 调整从叶子s出发的到根的一个序列
void Adjust(int *ls,int *b,int s)
{
int t = (s+k)/2;
while(t>0){
if(b[s]>b[ls[t]]){
int temp = s;
s = ls[t];
ls[t] = temp;
}
t = t/2;
}
ls[0] = s;
}
// 合并算法
void KMerge(int *ls)
{
int b[k+1],i,q;
for(i = 0; i < k; ++i)
b[i] = getnext(i);
// 让b[k]等于-1,让ls[i]都指向这个负数,也就是初始,让这些数字取得胜利,让叶子成为败者而覆盖其父节点。
b[k] = -1;
for(i=0;i<k;++i)
ls[i] = k;
for(i=k-1;i>=0;--i)
Adjust(ls,b,i);
while(b[ls[0]]!=MAXKEY){
q=ls[0];
printf("%d ",b[q]);
b[q] = getnext(q);
Adjust(ls,b,q);
}
}
int main()
{
int ls[5];
KMerge(ls);
return 0;
}