【编程珠玑】第一章 开篇

【编程珠玑】第一章 开篇

一. 题目

      如何给磁盘文件排序?

     问题描述:
     输入:一个最多含有n个不重复的正整数(也就是说可能含有少于n个不重复正整数)的文件,其中每个数都小于等于n,且    n=10^7。
     输出:得到按从小到大升序排列的包含所有输入的整数的列表。
     条件:最多有大约1MB的内存空间可用,但磁盘空间足够。且要求运行时间在5分钟以下,10秒为最佳结果。

二.分析

      1)基于磁盘的归并排序(耗时间)

     2)每个号码采用32位整数存储的话,1MB大约可以存储250 000 个号码,需要读取文件40趟才能把全部整数排序。(耗时间)

     3)位图法,采用一个1千万位的字符串表示每个数,比如{0,2,3}表示为   1  0 1 1 0 0 0 0 。(说明:左边第一位表示 0 第二位表示1 第三位表示 2 。如果有则表示为1,否则为0)遍历每一个整数,有则标记为1,否则标记为0。然后按顺序输出每个整数。这种方法实际需要1.25MB内存,如果可以方便弄到内存的话可以采用此种方法。

     4)假如严格限制为1MB,可以采用的策略:两次遍历或者除去第一位为0或1的整数。

         解释:考虑到没有以数字0或1开头的电话号码,可以省略对这些数的操作。

         两次遍历:对  1 ---4999 999之间的数排序,需要存储空间为:5000 000/8 =625 000 字节(8为一个字节中的位数) 对 5000 000 -10000 000 之间的数排序。 如果需要采用k趟算法,方法类似。

三. 算法实现

#include <stdio.h>  

#include <stdlib.h>  

#define SHIFT 5  //表示位移量

#define MASK 0x1F  //掩码

#define N 10000000  //表示有1000万个数

int a[1 + N/32];  //使用整形数组来模拟定义1000万个位的数组

void set(int i) {  a[i>>SHIFT] |=  (1<<(i & MASK)); } //设置位数组中的从0开始的第i位为1 

void clr(int i)  {   a[i>>SHIFT] &= ~(1<<(i & MASK)); }  //设置位数组中的从0开始的第i位为0

int  test(int i) { return a[i>>SHIFT] &   (1<<(i & MASK)); }  //取出从0开始的第i位的值,用于检测

int main()  

{       

       int i = 0;  

        //int  top = 1 + N/BITSPERWORD;  

        //memset(a, 0, sizeof(a)*sizeof(int)); 

       for(i=0;i<N;i++)

           clr(i);

       while (scanf("%d", &i))   

        set(i);  

        for (i = 0; i < N; i++)            

          if (test(i))   

          printf("%d\n", i);  

         return 0;  

}  

四. 参考来源

    1.  http://blog.csdn.net/tianshuai11/article/details/7555563

    2.  http://blog.csdn.net/ju136/article/details/6832331

    3. 《编程珠玑》读书笔记

                    

你可能感兴趣的:(【编程珠玑】第一章 开篇)