败者树

Posted beixiaobei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了败者树相关的知识,希望对你有一定的参考价值。

大文件排序

 

#include <stdio.h>
#define k 5
#define MAXKEY 10000
#define MINKEY -1
typedef int LoserTree[k];//表示非终端结点,由于是完全二叉树,所以可以使用一维数组来表示
typedef struct {
    int key;
}ExNode, External[k + 1];
External b;//表示败者树的叶子结点
//a0-a4为5个初始归并段
int a0[] = { 10,15,16 };
int a1[] = { 9,18,20 };
int a2[] = { 20,22,40 };
int a3[] = { 6,15,25 };
int a4[] = { 12,37,48 };
//t0-t4用于模拟从初始归并段中读入记录时使用
int t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0;
//沿从叶子结点b[s]到根结点ls[0]的路径调整败者树
void Adjust(LoserTree ls, int s) {
    int t = (s + k) / 2;//叶子结点对应根节点下标
    while (t > 0) {
        //判断每一个叶子结点同其双亲结点中记录的败者的值相比较,调整败者的值,其中 s 一直表示的都是胜者
        if (b[s].key > b[ls[t]].key) {//最开始,ls[t]是k,b[k]是MINKEY
            int swap = s;
            s = ls[t];
            ls[t] = swap;
            //ls[t] = s;
        }
        t = t / 2;
    }
    //最终将胜者的值赋给 ls[0]
    ls[0] = s;
}
//创建败者树
void CreateLoserTree(LoserTree ls) {
    b[k].key = MINKEY;
    //设置ls数组中败者的初始值
    for (int i = 0; i < k; i++) {
        ls[i] = k;
    }
    //对于每一个叶子结点,调整败者树中非终端结点中记录败者的值
    for (int i = k - 1; i >= 0; i--) {
        Adjust(ls, i);
    }
}

//模拟从外存向内存读入初始归并段中的每一小部分
void input(int i) {
    switch (i) {
    case 0:
        if (t0 < 3) {
            b[i].key = a0[t0];
            t0++;
        }
        else {
            b[i].key = MAXKEY;
        }
        break;
    case 1:
        if (t1 < 3) {
            b[i].key = a1[t1];
            t1++;
        }
        else {
            b[i].key = MAXKEY;
        }
        break;
    case 2:
        if (t2 < 3) {
            b[i].key = a2[t2];
            t2++;
        }
        else {
            b[i].key = MAXKEY;
        }
        break;
    case 3:
        if (t3 < 3) {
            b[i].key = a3[t3];
            t3++;
        }
        else {
            b[i].key = MAXKEY;
        }
        break;
    case 4:
        if (t4 < 3) {
            b[i].key = a4[t4];
            t4++;
        }
        else {
            b[i].key = MAXKEY;
        }
        break;
    default:
        break;
    }
}
//败者树的建立及内部归并
void K_Merge(LoserTree ls) {
    //模拟从外存中的5个初始归并段中向内存调取数据
    for (int i = 0; i <= k; i++) {
        input(i);
    }
    //创建败者树
    CreateLoserTree(ls);
    //最终的胜者存储在 is[0]中,当其值为 MAXKEY时,证明5个临时文件归并结束
    while (b[ls[0]].key != MAXKEY) {
        //输出过程模拟向外存写的操作
        printf("%d ", b[ls[0]].key);
        //继续读入后续的记录
        input(ls[0]);
        //根据新读入的记录的关键字的值,重新调整败者树,找出最终的胜者
        Adjust(ls, ls[0]);
    }
}
int main(int argc, const char * argv[]) {
    LoserTree ls;
    K_Merge(ls);
    return 0;
}

 

以上是关于败者树的主要内容,如果未能解决你的问题,请参考以下文章

多路平衡归并和败者树

多路平衡归并和败者树

一文读懂胜者树与败者树

败者树

算法-排序k路平衡归并与败者树

外排序 & 败者树 & 多路归并-学习