"编程珠玑" 第一章 磁盘文件排序问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rongdongzhu1/article/details/48276877
问题描述:
输入: 一个最多包含n个正整数的文件,每个数都小于n,其中 n = 10^7.如果在输入文件中
有任何整数重复出现就是致命错误.没有其他数据与该整数相关联.

输出: 按升序排列的输入整数的列表

约束: 最多有(大约) 1MB 的内存空间可以使用,有充足的磁盘空间可以使用,运行时间最多
几分钟,运行时间最多为10s就不需要进一步优化了

问题分析:
显而易见 说到排序大家第一个必然想到 快速排序, 

方案一: 快速排序 
那不妨让我们先计算下快速排序整个文
件所需要的空间大小,假设数据以 32位int型存放
((10^7) * 32) /(8*1024*1024) = 38.14MB
38.14 / 1 = 39 次
是的 我们至少需要 (39 + 1) 次快速排序,需要将数据分40次读入内存.那么时间复杂度可想
而知.
方案二: 归并排序
有兴趣可以去查一下

方案三: 我理解为 基于hash的排序 下面我详述一下
算法思想:
1 用 "位图"(bitmap) 这种数据结构来进行存储数据.
位图: 该数据结构描述了一个有限定义域内的稠密集合,其中的每一个元素至多出现一次
并且没有其他任何数据与该元素相关联.即使这些条件没有完全满足,也可以用有限定义域
内的键作为一个表项更复杂的表格索引.
2 类似于hash排序的思想,用位图存放所需要的内存大小为
(10^7)/(8*1024*1024) = 1.19MB
将内存空间的需求瞬间缩小到 1.19MB 使一次性读入成为可能
算法代码:

以下代码仅作思想体现,实际意义并不大


			
#include <iostream>
#include <cmath>
#define MAX 4

using namespace std;

// 初始化字典数组
int Dic[32] = {0};

void InItDic(){
    for(int i = 0;i<32;i++)
        Dic[i] = pow(2,i);

}

int main(){
	// 申请大小为 312500的数组,当然直接申请这么大的很容易崩溃,不推荐
    int array[312500] = {0};
    int i;
    int Wait[MAX] = {0};

    InItDic();

	// 生成待排序资料 也可以从硬盘中读取
	
	for(i=0;i<MAX;i++){
        Wait[i] = MAX - i - 1;
    }

	// 进行排序
	/*
		具体解析:
			一个int有32位,即 312500 * 32 = 10^7
			将 待排序数/32 计算出应该存储这个位的数字编号
			将 待排序数%32 计算出存储在这个数的哪一二进制位
			然后将这一位置为1,我在此采用置1的方法是,将表示该位的数
			与原数做 按位或 运算
			
			最后按位遍历 得到的就是升序序列
	*/
    for(i=0;i<MAX;i++)
        array[Wait[i]/32] |= Dic[Wait[i]%32];

    cout << array[0];
}


// 个人见解 欢迎指正 不胜感激


猜你喜欢

转载自blog.csdn.net/rongdongzhu1/article/details/48276877