下午看完编程珠玑第一章,感觉很不错!如作者所说:阅读本书一个提示,不要太快, 一次阅读一章。集中精力思考,解答课后习题。 写总结就是在刚弄懂的时候,这时候是最恰当的时候,最容易接受。 题目要求:一个最多含有1000万个整数的文件,整数没有重复,请输出升序排列。 (约束):最多1M内存,时间10S。 题目很简单,但是分析的过程很经典。 刚开始想法,排序呗。。可是时间要求10S,内存要求1M,以往像严蔚敏《数据结构》 课本上最后的外部排序(归并排序),时间肯定不行。大家注意,这里主要的限制是1M 内存。在TCPL中,作者说:在存储空间很宝贵的情况下,有可能需要将多个对象保存在 一个机器字中。一种常用的方法是使用类似于编译器符号表的单个二进制位标志集合。 最简洁的方法就是使用一个char或int对象中的位标志集合。 所以此题目的解法就不自觉的运用位图来实现。1M=1024KB约等于1000000B。也就 是8000000位。可是题目有10000000个整数,也就是我们要用800万位来存储1000万 的整数。 注意如果内存不是严格的1M内存,我们可以找出200个稀疏位,1位代表1个整数。 可是如果内存是严格的受限制1M之内,那么我们就要想别的方法(下文会提到)。 我们使用的数据结构是整型数组,int a[1+10000000/32],因为int是32位,而除 法又是地板除,所以我们将1000个整数就存储在int a[]数组中。1位代表1个整数,如 果整数在里面,就把位置1,否则置0(前提是整数无重复,有重复的情况下面讨论) 然后算法逻辑很简单,先把所有位置清0,设置相应的位,最后检测输出整数。 算法源代码(作者源代码,非本人所写):#include <stdio.h> #define BITSPERWORD 32 #define SHIFT 5 #define MASK 0x1F #define N 10000000 //整型数组存储1000万个整数,1个位存储1个 //每一个元素是int,是32位 int a[1 + N/BITSPERWORD]; void set(int i) { //i>>SHIFT,也就是除以32,求出是第几个int //i & MASK,也就是i%32,因为int是32位 //1左移对应位数,即把1跟对应整型数字的位进行或运算,来置位。 //随着i增大,32个一循环,就可以把 //每一个int的32位都来置位,这样就完成了位运算。 //位运算请详细参考TCPL。 a[i>>SHIFT] |= (1<<(i & MASK)); } void clr(int i) { a[i>>SHIFT] &= ~(1<<(i & MASK)); } int test(int i) { return a[i>>SHIFT] & (1<<(i & MASK)); } int main() { int i; for (i = 0; i < N; i++) clr(i); while (scanf("%d", &i) != EOF) set(i); for (i = 0; i < N; i++) if (test(i)) printf("%d\n", i); return 0; }
补充:上面代码里的位运算,讲的有点不太好,其实通俗的讲就是:
i>>SHIFT:利用除法,确定是整型数组哪一个int.
1<<(i&MASK):利用取余,确定该置位的是哪一位。
现在,特殊情况我们已经解决(1.不准重复 2.内存不是严格的1M)
那么我们来解决这两个一般性问题:
1.如果整数可以重复,那怎么办,就像书上说:可以重复10次。原来1位存储1个数字
但是现在肯定不行,我们还要存储数量,于是我们在用4位(16次)来存储数量,这样我
们就需要用4000万位来存储1000万的整数了。
2.如果内存严格的1M怎么办?我们怎么来扩展内存呢?一般的做法就是:既然1次我
们存储不了,那么我们可以把1000万分成2趟来排序,先用5000000个位的存储空间来
存储0~4999999之间的整数,第二趟排序5000000~9999999的整数。K趟算法可以在KN
的时间开销和N/K的空间开销完成排序。
至此,已总结结束,写作是为了更好的思考!好好学习,为找工作而努力!
编程珠玑第一章
最新推荐文章于 2021-06-11 18:13:25 发布