电话号码排序

编程珠玑第一章,电话号码排序,问题是这样的,给你大约1000万个数字,让你用最快的方式进行排序,限制如下:

1. 内存大约1M

2. 数字都是整数,且不重复

3. 数字的范围最大是7位数。


文章提到了大约三种解法,

第一种是归并算法,只不过不在内存,在外存上做归并排序。大致思路是将原始文件读入,然后按照数字的大小划分10份,写到10个文件里。

这样每个文件就小于1M,然后对每个文件进行排序,排序之后,将文件合并。由于file1<file2<...<file10。所以合并很简单,直接依次读一遍,再写文件即可。

读次数:1+10+10

写次数:  10+10+1


第二种二种比较傻,分多次读,每次只读i~ j的数字,然后对其排序,并输入到文件。这个方法不再赘述。


第三种就是使用bitmap,思路就是把一个32位的整数用来存32个数字,比如,如果数字i出现了,则该数的二进制的第i位为1,否则为0。这样1000万个数字大约要1.25M.

首先读入所有的数字,存入bitmap,然后遍历bitmap,如果第i位为1,表示出现过,则输出到文件,否则,不输出。

下面是标准答案,感觉位运算写的很好,很高效,学习下:
[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include <cstdio>  
  3. using namespace std;  
  4.   
  5. #define BITSPERWORD 32  
  6. #define SHIFT 5  
  7. #define MASK 0x1F  
  8. #define N 1000000  
  9. int a[1+N/BITSPERWORD];  
  10.   
  11. /* 
  12.  * 参考代码写的bitmap实在是太巧妙了,全部都是移位和位运算,非常高效。 
  13.  * 常用技巧: 
  14.  * 1. 求n除以2^i的余数 
  15.  *   最低效:n%(2^i) 
  16.  *   低效:n-(n/2^i)*2^i 
  17.  *   高效:n-(n>>i)<<i 
  18.  *   最高效: 从上面的过程可以看出,求除以2^i后的余数即保留低i位的二进制,其余位变0 
  19.  *       #define MASK 0x1F (假设是i=5) 
  20.  *       n&MASK 
  21.  * 
  22.  * 2. 将n的第i个二进制位置1或0 
  23.  *    置1:n=n|(1<<i) 
  24.  *    置0: n=n&~(1<<i) 
  25.  */  
  26.   
  27. void set(int i) { a[i>>SHIFT]|= (1<<(i&MASK)); }  
  28. void clr(int i) { a[i>>SHIFT]&= ~(1<<(i&MASK)); }  
  29. int test(int i) { return a[i>>SHIFT]&(1<<(i&MASK)); }  
  30. void reset() { memset(a,0,sizeof(a)); }  
  31.   
  32. int main(){  
  33.     int i;  
  34.     int n,m;  
  35.     reset();  
  36.     scanf("%d",&n);  
  37.     for(i=0;i<n;i++){  
  38.         scanf("%d",&m);  
  39.         set(m);  
  40.     }  
  41.     for(i=0;i<100;i++)  
  42.         if(test(i))  
  43.             printf("%d\n",i);  
  44.     return 0;  
  45. }  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值