问题描述
对磁盘内的文件进行排序:
- 输入:一个文件包括n个整数,每个整数都小于n,n = 10^7.文件内没有重复的数字
- 输出:以升序排列的数字序列
约束:内存最多使用1M,有充足的磁盘空间,运行时间最多为几分钟,最好控制在10秒钟
对于这个问题,书上给了3种方法:
- 使用MergeSort来排序输入文件,但是由于文件中整数过多,还是要花费几天的时间。
- 使用QuickSort排序,需要读取输入文件40次,但只输出一次。
- 结合上述两种方法的优点
用bitmap的方法,例如集合{1,2,3,5,8,13},我们可以用字符串
0 1 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 来表示,那么10^7个整数就可以用1000万位来表示,只要输入文件中存在那个数字,则就表示为“1”,反之为“0”。所以整个过程可以表示为以下伪代码:
/* 第一个阶段:初始化集合 */
for i = [0,n)
bit[i] = 0;
/* 第二个阶段:将输入文件的数用位图表示出来 */
for each i in the input file
bit[i] = 1;
/* 第三个阶段:将排序结果写在输出文件上 */
for i = [0.n)
if bit[i] == 1
write i on the output file
习题
- 如果空间足够,你将如何使用一种语言来实现排序
//快速排序
int Patition(ElemType A[],int low,int high)
{
int pivot = A[low];
while(low < high)
{
while(low < high && A[high] >= pivot) high--;
A[low] = A[high];
while(low < high && A[low] <= pivot) low++;
A[high] = A[low];
}
A[low] = pivot;
return low;
}
void QuickSort(ElemType A[],int low,int high)
{
if(low < high)
{
int pivot = Patition(A,low,high);
QuickSort(A,low,pivot-1);
QuickSort(A,pivot+1,high);
}
}
2.如何用二进制逻辑运算符(or,and,shift)来实现位向量呢?
//如何使用位逻辑运算(例如与、或、移位)来实现位向量
/* Copyright (C) 1999 Lucent Technologies */
/* From 'Programming Pearls' by Jon Bentley */
/* bitsort.c -- bitmap sort from Column 1
* Sort distinct integers in the range [0..N-1]
* 排序在0到N-1范围内的无重复整数
*/
#include <stdio.h>
#define BITSTEPWORD 32 //表示一个整型含有32个位
#define SHIFT 5 //单次位移量
#define MASK 0x1F //掩码
#define NUM 10000000 //表示1000万个整数
int array[1 + NUM / BITSTEPWORD];//使用整型数组模拟定义1000万个位的数组
/*功能:设置位数组中的从0开始的第i位为1
*参数:需要设置为1的位
*/
void set(int i)
{
array[i >> SHIFT] |= (1 << (i & MASK));
}
/* i >> SHIFT 的功能是先选中i所在的int小组,共有1 + NUM / BITSTEPWORD个小组然后(1 << (i & MASK))的功能就是选中小组中的第几位,因为数组从0开始,所以要左移一位,最后 ||就起到了设置“1”的作用
*/
/*
*功能:设置位数组中的从0开始的第i位为0
*参数:需要设置为0的位
*/
void clr(int i)
{
array[i >> SHIFT] &= ~(1 << (i & MASK));
}
/*
*功能:取出从0开始的第i位的值,用于检测
*/
void test(int i)
{
return array[i >> SHIFT] & (1 << (i & MASK));
}
int main(void)
{
int i;
clear();
for( i = 0; i < 100; i++ )
set( i*2 );
for( i = 0; i < 200; i++ )
printf("%d",test(i) ? 1:0 );
puts("");
return 0;
}
3.在系统中实现位图排序,并测试运行时间,且和第一题的快排进行比较。
4.生成[0,n)之间k个不重复的数字
int array[n + 1];
void make_data(int n)
{
if(n <= 0)
{
return;
}
for(int i = 0; i < n; i++)
{
array[i] = i + 1;
}
for(int i = 0; i < n; i++)
{
int ii = (rand() * RAND_MAX + rand()) % n;
int jj = (rand() * RAND_MAX + rand()) % n;
swap(array[ii], array[jj]);
}
}