编程珠玑(一)
今天有点时间,打算看点编程算法相关的东西,但是又不想单单看将数据结构和算法的课本,那些课本都太枯燥,提不起兴趣来学习。今天在网上看到《编程珠玑》这本书,下下来研究一下,讲的都是算法和问题如何求解的,通过一个例子来讲解算法,这很有意思,国外的大牛讲的也很通俗易懂,计划有时间要多看看这本书。
今天看了第一章的例子,问题的需求如下:输入:输入的是一个文件,至多包含n个正整数,每个正整数都要小于n,n很大,如果输入时有一个整数出现了两次,就会产生一个致命的错误。输出:以赠序形式输出排序之后的整数列表。
要解决这个问题,首先要生成自己的测试数据,一开始看的时候自己生成测试数据这块还真的把我给蒙住了,但是看到源码之后才恍然大悟。原来先生成0到n的数据,然后随机的选择一些数据将他们打乱就行了,就这么简单。附带源码如下:
int randint(int a, int b) { return a + (RAND_MAX * rand() + rand()) % (b + 1 - a); } int* randvector(int num) { int i,k,t,p; k=num/10; int *x=new int[num]; for (i=0;i<num;i++) { x[i]=i; } for (i=0;i<k;i++) { p=randint(i,num-1); t=x[p]; x[p]=x[i]; x[i]=t; } return x; }
intrand函数式生成a和b之间的数,randvector是将生成的结果放在一个数组中。
为了解决问题中存贮空间的不足,作者采用了位图和位向量的概念,首先建立一个n长度的数组,将数组置零,发现测试数据中有数据m出现,就将数组的m位置1,输出的时候,按照数组中1
的位置将数据所在的位置输出就可以,这样通过转换实现了排序,很巧妙。
源码中是大牛写的代码,很是节省内存,我不能用,自己重写了。
大牛代码:
#define BITSPERWORD 32 #define SHIFT 5 #define MASK 0x1F #define N 10000000 int a[1 + N/BITSPERWORD]; void set(int i) { 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)); }
自己写的完整的代码如下:
#include <iostream> #include <vector> #include <algorithm> #include <time.h> using namespace std; #define BITSPERWORD 32 #define SHIFT 5 #define MASK 0x1F #define N 10000000 int a[1 + N/BITSPERWORD]; void set(int i) { 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 randint(int a, int b) { return a + (RAND_MAX * rand() + rand()) % (b + 1 - a); } int* randvector(int num) { int i,k,t,p; k=num/10; int *x=new int[num]; for (i=0;i<num;i++) { x[i]=i; } for (i=0;i<k;i++) { p=randint(i,num-1); t=x[p]; x[p]=x[i]; x[i]=t; } return x; } void Set(int a[],int k) { a[k]=1; } int Test(int a[],int k) { if (a[k]) { return k; } } void main() { srand((unsigned) time(NULL)); int num=2000; int *x=randvector(num); for (int i=0;i<num;i++) { cout<<x[i]<<endl; } cout<<"--------------------"<<endl; // vector<int> intv; // for (i=0;i<num;i++) // { // intv.push_back(x[i]); // } // sort(intv.begin(),intv.end()); // for (vector<int>::iterator iter=intv.begin();iter!=intv.end();iter++) // { // cout<<*iter<<endl; // } int *flag=new int[num]; memset(flag,0,sizeof(int)*num); for (int j=0;j<num;j++) { Set(flag,x[j]); } for (int k=0;k<num;k++) { cout<<Test(flag,k)<<" "; } }