《编程珠玑》笔记1 开篇
为了克服自己看过就忘的毛病,现在决定用文字把这些东西记录下来。以下大部分是对书上内容的总结。
1.开篇第一部分主要是使用位图法进行排序。
问题描述:一个最多包含n个整数的文件,每个数小于m,n=10^7,数据不重复(所以m>=n),且随机出现。对该数据进行排序,最多有1MB的内存空间可用。
2.首先分析问题,对n=10^7个数据,设每个int型为4字节,那么总共需要40MB的大小。所以如果要使用归并排序,需要进行40趟磁盘IO,这显然在时间上是难以忍受的。
考虑该问题的特点:1)数据大小范围有限;2)不重复。
针对第一个特点,计数排序是一个很好的方法,我们可以申请一个m大小的数组,用对应的值来标记该数是否存在。在考虑到第二个特点,可以用某一位是1还是0就可以完成标记。
假设有m=n,那么此时需要大小为 10^7 bit = 1.25MB。(注意不要用bool变量的数组来标记是否存在,因为bool变量占一个字节Byte,所以总大小仍需10MB)
代码实现:(直接使用C++中bitset类模板来实现)
1 #include<iostream> 2 #include<fstream> 3 #include<bitset> 4 using namespace std; 5 6 #define M 10 //the range 7 #define N 5 //the number 8 9 int main(int argc, char **argv) 10 { 11 ifstream fin(argv[1]); 12 ofstream fout(argv[2]); 13 bitset<M> data; //the initial ensure that every bit is 0 14 data.reset(); 15 16 int temp; 17 while(fin >> temp) 18 data.set(temp); 19 20 for(int i = 0; i < M; i++) 21 { 22 if(data.test(i)) 23 fout << i << " "; 24 } 25 return 0; 26 }
3.习题:
3.1 C标准库中的比较函数:
#include <stdlib.h>
void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );
base为基本数组,num为元素个数,size为每个元素的大小(一般为sizeof(int)作为参数),最后一个是比较器,大于正,小于负,相等0
C++中STL提供了很多排序函数位于<algorithm>中。
3.2主要实现如下三个操作:
#define BITSPERWORD 32 #define SHIFT 5 //used to divide 20 #define MASK 0x1F #define N 10000000 int a[1+N/BITSPERWORD]; // 设置为1 就是将该值与一个 只有第i位为1,其余为0的数进行 位或“|”。i>>SHIFT表示 i/32,就得到相应数组元素。 // i&MASK得到最后5位值,即 i%32,表示i在该元素的第几位。然后将0x0001左移这么多位即可 void set(int i) { a[i>>SHIFT] |= (1<<(i&MASK)); } //clr就是设置为0,将该值与 只有第i位为0, 其余为都为1的值 位与 void clr(int i) { a[i>>SHIFT] &= ~(1<<(i&MASK)); } //test是判断第i位值,将该值与 只有第i位为1,其余位都为0的值 进行 位与,若原值的第i位也为1, 则结果为1,否则结果为0。 //与 int get(int i) 具有同样的函数内容 int test(int i) { return a[i>>SHIFT] & (1<< (i&MASK)); }
3.3
3.4 随机生成小于n且没有重复k个整数的算法
这部分主要在第12章讲述
3.5 因为前面可以看到位图法要1.25MB的内存空间,如果严格限制1MB的话。
这时需要使用 多趟算法,第一遍遍历整个输入数据时,只处理其中范围在0~499 9999内的数据,这样只需要500 0000/8=0.625MB即可。第二趟再次从头读取数据,对处于后面范围的数据进行排序处理。
3.6 如果每个整数最多出现10次,那么0~10就需要4个bit,所以一个整数占4个bit位。总共需1.25*4 = 5MB内存。简单的方法,就是5趟算法即可。
3.7 对1.4节的程序,要做的就是 检查不合法输入 和 对特殊输入进行处理:
for i = [0,n) bit[i] = 0 for each i in input file Assert(i>=0 && i <= n) if(bit[i] = 1) error("duplicate data!"); bit[i] = 1; for i = [0,n if(bit[i] == 1) write i to output file
可能理解有误,应该是可能出现字母等非数字,然后如何对这些非数字实现bitmap(使用一个特定的hash将出现的负数,字母hash到正确的结构中去?)
3.8 先对区号进行bitmap排序,然后在对每一个区号,遍历一遍输入数据,进行bitmap排序