码迷,mamicode.com
首页 > 其他好文 > 详细

看数据结构写代码(66) 败者树

时间:2015-05-05 10:45:00      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:败者树   外部排序   败者树c语言描述   

计算机的 内存 是 有限的,无法 存入 庞大的数据。当 遇到 大数据需要排序时,我们 需要 将 这些 数据 分段 从 硬盘里 读到 内存中,排好序,再 写入到 硬盘中,这些段 叫做 归并段。最后将 这些 分段 合并 成 一个 最终  完整 有序的 数据。 

这里 操作的 时间 =  内部 排序 时间 +  外存读写时间 + 内部归并所需时间。

其中 外存 读写时间 最耗时,外存读写时间 = 读写次数 * 读写数据的时间 ,读写 数据的时间 因 设备 性能 而 影响,我们 无法控制,我们 只能 控制 读写次数。读写 次数 和 归并过程 有关。 当 我们 采用 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;
}


假设 内存 一次 只能 载入 3 个数据(INT_MAX不算):

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},
};

最终 归并 这些 数据的 结果为:

技术分享


看数据结构写代码(66) 败者树

标签:败者树   外部排序   败者树c语言描述   

原文地址:http://blog.csdn.net/fuming0210sc/article/details/45498039

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!