编程算法 - K路归并排序(k-way merge sort) 代码(C++)

K路归并排序(k-way merge sort) 代码(C++)

本文地址: http://blog.csdn.net/caroline_wendy

K路归并排序作为经典的外部排序算法, 是程序员必须要掌握的.

知识概念参考: <数据结构>

主要思想: 在k个已排序的文件中, 选择第一个值, 采用败者树, 更新二叉树结构, 最终选择最优值.

代码仅供参考, 如最小值用(-1)代替, 最大值用(100)代替.

/*
 * main.cpp
 *
 *  Created on: 2014年9月11日
 *      Author: Spike
 */

#include <fstream>
#include <iostream>
#include <vector>

using namespace std;

class KWayMergeSort
{
public:
	KWayMergeSort(vector<ifstream*>& vif) :
		m_vifs(vif), m_ofs("out.txt") { }

	void calculate() {
		/* 分别从k个输入归并段读人该段当前第一个记录的关键字到外结点 */
		for(int i = 0;i < k;++i) {
			input(i, b[i]);
		}

		createLoserTree();

	    while(b[ls[0]] != MAXKEY){
	        /* q指示当前最小关键字所在归并段 */
	        int q = ls[0];

	        /* 将编号为q的归并段中当前(关键字为b[q].key)的记录写至输出归并段 */
	        cout << b[q] << " ";
	        m_ofs << b[q] << " ";

	        /* 从编号为q的输入归并段中读人下一个记录的关键字 */
	        input(q, b[q]);
	        /* 调整败者树,选择新的最小关键字 */
	        adjust(q);
	    }

	    /* 将含最大关键字MAXKEY的记录写至输出归并段 */
        cout << endl;
        m_ofs << endl;
	}
private:
	void input (int i, int& b) {
		if ((*m_vifs[i]).good()) {
			(*(m_vifs[i])) >> b;
		}
	}

	/**
	* 已知b[0]到b[k-1]为完全二叉树ls的叶子结点,存有k个关键字,沿从叶子
	* 到根的k条路径将ls调整成为败者树。
	*/
	void createLoserTree() {
	    b[k] = MINKEY;

	    /* 设置ls中“败者”的初值 */
	    for(int i = 0; i < k; ++i){
	        ls[i] = k;
	    }

	    /* 依次从b[k-1],b[k-2],…,b[0]出发调整败者 */
	    for(int i = k - 1; i >= 0; --i){
	        adjust(i);
	    }
	}

	void adjust(int i) {
		/* ls[t]是b[s]的双亲结点 */
		int t = (i + k) / 2;
		while (t > 0) {
			/* s指示新的胜者 */
			if (b[i] > b[ls[t]]) {
				int tmp = i;
				i = ls[t];
				ls[t] = tmp;
			}
			t = t / 2;
		}
		ls[0] = i;
	}

private:
	static const int k = 4;
	static const int MINKEY = -1;
	static const int MAXKEY = 100;
	int b[k+1]; //败者树的叶子节点
	int ls[k]; //败者树的其余节点
	vector<ifstream*> m_vifs;
	ofstream m_ofs;
};

int main(void) {

	vector<ifstream*> vif;
	ifstream* ifs0 = new ifstream("f0.txt");
	ifstream* ifs1 = new ifstream("f1.txt");
	ifstream* ifs2 = new ifstream("f2.txt");
	ifstream* ifs3 = new ifstream("f3.txt");
	vif.push_back(ifs0);
	vif.push_back(ifs1);
	vif.push_back(ifs2);
	vif.push_back(ifs3);

	KWayMergeSort k(vif);
	k.calculate();

	delete ifs0;
	delete ifs1;
	delete ifs2;
	delete ifs3;

	return 0;

}

待排序文件, 最后一个是标记, 用于停止更新败者树:

f0: 5 16 49 52 78 100
f1: 7 12 25 84 91 100
f2: 29 38 57 66 71 100
f3: 9 22 47 48 59 100

输出:

5 7 9 12 16 22 25 29 38 47 48 49 52 57 59 66 71 78 84 91

时间: 2024-08-27 13:55:09

编程算法 - K路归并排序(k-way merge sort) 代码(C++)的相关文章

编程算法 - n个骰子的点数(非递归) 代码(C)

n个骰子的点数(非递归) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 把n个骰子仍在地上, 所有骰子朝上一面的点数之和为s. 输入n, 打印出s的所有可能的值出现的概率. 每次骰子的循环过程中, 本次等于上一次n-1, n-2, n-3, n-4, n-5, n-6的次数的总和. 代码: /* * main.cpp * * Created on: 2014.7.12 * Author: spike */ #include <stdio.

编程算法 - 萨鲁曼的军队(Saruman&#39;s Army) 代码(C)

萨鲁曼的军队(Saruman's Army) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 直线上有N个点, 每一个点, 其距离为R以内的区域里, 必须带有标记的点, 本身的距离为0. 尽可能少的添加标记点, 至少要有多少点被加上标记? 贪心算法, 从最左边的点开始, 依次查找距离为R需要添加标记的点, 直到结束. 代码: /* * main.cpp * * Created on: 2014.7.17 * Author: spike */

编程算法 - 和为s的连续正整数序列 代码(C)

和为s的连续正整数序列 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 输入一个正数s, 打印出所有和为s的连续正数序列(至少含有两个数). 起始于1, 2, 相加, 如果相等则返回, 如果小于, 则前端递增右移, 如果大于, 则后端递增右移, 一直到后端移动到s的一半位置. 因为两个数, 小数为一半, 大数为一半加一, 则必然结束. 代码: /* * main.cpp * * Created on: 2014.6.12 * Author:

编程算法 - 不能被继承的类(模板参数友元) 代码(C++)

不能被继承的类(模板参数友元) 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 用C++设计一个不能被继承的类. 可以使用模板类模板参数友元, 模板类私有构造函数, 类虚继承这个模板类, 如果类被其他类继承时, 则虚继承会直接调用模板类, 无法构造. 代码: /* * main.cpp * * Created on: 2014.7.13 * Author: Spike */ /*eclipse cdt, gcc 4.8.1*/ #inc

编程算法 - 圆圈中最后剩下的数字(递推公式) 代码(C++)

圆圈中最后剩下的数字(递推公式) 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 0,1...,n-1这n个数字排成一个圆圈, 从数字0開始每次从这个圆圈里删除第m个数字. 求出这个圆圈里最后剩下的数字. 能够推导出约瑟夫环的递推公式, 使用循环进行求解,  时间复杂度O(n), 空间复杂度O(1). 代码: /* * main.cpp * * Created on: 2014.7.12 * Author: spike */ #incl

编程算法 - 圆圈中最后剩下的数字(循环链表) 代码(C++)

圆圈中最后剩下的数字(循环链表) 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 0,1...,n-1这n个数字排成一个圆圈, 从数字0开始每次从这个圆圈里删除第m个数字. 求出这个圆圈里最后剩下的数字. 使用循环链表, 依次遍历删除, 时间复杂度O(mn), 空间复杂度O(n). 代码: /* * main.cpp * * Created on: 2014.7.13 * Author: Spike */ #include <iostr

专访POWER 8编程挑战赛选手黄文超:非专科生的编程算法之路

9月23日,IBM和CSDN联合宣布“ 2014 POWER 8极限性能挑战赛 ”正式启动.此次大赛主要面向广大CSDN注册开发者,大赛以云计算的方式为开发者提供了POWER 8开发环境,开发者利用POWER 8的特性,基于不同场景进行应用开发.此次大赛,不仅使更多的开发者充分利用了POWER 8,也为开发者.技术达人提供一个展示自我的舞台. 正如大赛发布仪式上,IBM大中华区副总裁侯淼所言,之所以要支持这样一个大赛,目的就是希望吸引更多的开发者去开发一些新的算法,把整个POWER 8引擎的能力

编程算法 - 两个升序列的相同元素 代码(C)

两个升序列的相同元素 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 两个升序列的相同元素, 需要使用两个指针, 依次遍历, 如果相等输出, 如果小于或大于, 则增加一个指针. 直到输出所有的值. 代码: /* * main.cpp * * Created on: 2014.9.19 * Author: spike */ #include <stdio.h> int Common(int data1[], int length1, int dat

编程算法 - 数组中出现次数超过一半的数字 代码(C)

数组中出现次数超过一半的数字 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 数组中有一个数字出现的次数超过数组长度的一半, 请找出这个数字. 1. 使用高速排序(QuickSort)的方法, 把中值(middle)和索引(index)匹配, 输出中值, 并检測是否符合要求. 2. 使用计数方法依次比較. 代码:  方法1: /* * main.cpp * * Created on: 2014.6.12 * Author: Spike */