计算机的 内存 是 有限的,无法 存入 庞大的数据。当 遇到 大数据需要排序时,我们 需要 将 这些 数据 分段 从 硬盘里 读到 内存中,排好序,再 写入到 硬盘中,这些段 叫做 归并段。最后将 这些 分段 合并 成 一个 最终 完整 有序的 数据。
这里 操作的 时间 = 内部 排序 时间 + 外存读写时间 + 内部归并所需时间。
其中 外存 读写时间 最耗时,外存读写时间 = 读写次数 * 读写数据的时间 ,读写 数据的时间 因 设备 性能 而 影响,我们 无法控制,我们 只能 控制 读写次数。读写 次数 和 归并过程 有关。 当 我们 采用 2路 归并 和 5路 归并,显然 5路 归并的 所 读写的 次数 更少。(具体 看 课本)。可是 当 我们扩大 归并的 路树的同时,内部 归并的 时间 却 因此 上升。
我们 用 败者树 来解决 由 归并的 路数 增加 而 导致的 内部归并 时间 上升的 问题。
败者树 和 胜者树是 个 相反的概念,败者树的 父节点 保存 失败者,而 胜者树 的 父节点 保存 胜利者。他们 都是 完全二叉树,并且 都是 将 胜利者 继续 根 上层 继续 比较。
下面 给出 败者树的 代码:
欢迎指出 代码不足
// LoseTree.cpp : 定义控制台应用程序的入口点。
//败者树,父节点保存失败者的信息,胜利者继续 比赛
#include "stdafx.h"
#include <climits>
#define K 5//5路平衡归并
#define MEM_SIZE 4//内存最多存储3组数据.(多加了一个最大值数据)
typedef int LoseTree[K];//败者树的非终端节点
typedef struct ExNode{//败者树的叶子节点
int key;
}External[K+1];
//测试数组,假设 内存只能 放入 3组数据,并且 内存 已经将这些数据排好序了。
//现在 需要归并这些数据
static int testArray[K][MEM_SIZE] = {
{10,15,16,INT_MAX},
{9,18,20,INT_MAX},
{20,22,40,INT_MAX},
{6,15,25,INT_MAX},
{12,37,48,INT_MAX},
};
//调整函数,和 所有 祖先比较,替换败者 和 最终胜利者 t[0]
void adjust(LoseTree t,External ex,int i){
int f = (i + K) / 2;
while (f > 0){
if (ex[i].key > ex[t[f]].key){
int temp = i;
i = t[f];//i 保存 胜利者,继续 比较
t[f] = temp;//有新的败者了.
}
f = f / 2;
}
t[0] = i;//最终胜利者
}
//创建败者树..
void createTree(LoseTree tree,External ex){
for (int i = 0; i < K; i++){//初始化叶子节点
ex[i].key = testArray[i][0];
}
ex[K].key = INT_MIN;//为了让第一次 所有 都是 失败者
for (int i = 0; i < K; i++){//初始化非叶子节点,
tree[i] = K;
}
for (int i = K-1; i >= 0; i--){//调整叶子节点,顺序不能反
adjust(tree,ex,i);
}
}
void inputNewKey(External ex,int winIndex){
ex[winIndex].key = testArray[winIndex][1];
//前移
for (int i = 0; i < MEM_SIZE -1; i++){
testArray[winIndex][i] = testArray[winIndex][i+1];
}
}
//归并函数
void K_Merge(){
LoseTree t;//非叶子节点
External ex;//叶子节点
createTree(t,ex);
int winIndex = t[0];//胜利者 坐标
while (ex[winIndex].key != INT_MAX){
printf("%d\t",ex[winIndex].key);
inputNewKey(ex,winIndex);
adjust(t,ex,winIndex);
winIndex = t[0];
}
}
int _tmain(int argc, _TCHAR* argv[])
{
K_Merge();
return 0;
}
static int testArray[K][MEM_SIZE] = {
{10,15,16,INT_MAX},
{9,18,20,INT_MAX},
{20,22,40,INT_MAX},
{6,15,25,INT_MAX},
{12,37,48,INT_MAX},
};
最终 归并 这些 数据的 结果为: