编程珠玑 第一章习题解答

4.生成[0,n)的之间k个不重复的随机整数。
#include
#include
#include
#include
using namespace std;
const int N = 10000000;
const int K = 10000000;
int randint( int l, int r ){
    return rand() % ( r-l ) + l;
}
int a[ N ];
int main(void){
    for( int i = 0; i < N; i++ )
        a[i] = i;
    for( int i = 0; i < K; i++ ){
        swap( a[i], a[ randint(i,N) ] );
        printf("%d\n",a[i]);
    }
    return 0;
}

5.如果1MB是严格控制的空间,如果数据有1.25MB的bit数目。那么应该是需要读取2次。可以将输入文件分成两分,第一份保存[0,5000000)的数,第二个文件保存[5000000,10000000)的数字,然后分别进行排序,所用内存就可以降到1MB以内。如果我们把文件分成k份(每份都存一定区间的数),那么就可以在nk的时间,n/k的空间内完成排序。

6.如果每个数据出现最多10次,那么需要4个bit位来统计一个数。可以类比第五题,可以分成4份,在n/4的空间内完成。同样,当保存数字信息的量变化时,分成更多份,就可以在更小的空间内完成。

7.如果某个数出现超过一次的话,会发生什么?

      会被忽略掉, 因为原来的程序本身就是用来处理只出现一次的情况的。

在这种情况下,如何修改程序来调用错误处理函数?

    while (scanf("%d", &i) != EOF) 
    if(test(i)) call_error_fun(); 
    else set(i); 

 当输入整数小于零或大于等于n时,又会发生什么?

      会出现访问越界的情况。-1访问时,会访问a[-1]的31个bit位。

如果某个输入不是数值又如何?在这些情况下,程序该如何处理?

    输入可能是浮点数,或是字符什么的~~ 可以先读入字符串,再用atoi转换成为整形数,如果失败,则进行出错处理。

8.免费电话号码至少有800,878,888等,那么如何查看一个号码是否是免费号码。?

第一种方案:如果是一千万个电话号码都有可能成为免费号码,那么至需要1.25MB * (免费号码前缀个数)。

第二种方案:省空间,多次扫描文件:

                  1、首先扫描整个文件,看有哪个免费号码前缀。以及每个免费号码前缀下的号码个数。

                  2、设置区间映射表:比如800前缀有125个免费号码,找到最大的数,与最小的数,差值做为bit长度。

第三种方案:建立索引的方式来进行处理。以最后7位为索引,后面800,878什么的,为值。如果不是免费号码,应该是不用加入到这个hash表中。

9.本题值得一说。

初始化空间需要大量时间,不过我们的应用只需要其中一点点空间,比如1000000的位图,我们只用到其中的10位,怎样节省时间?题目中提示,可以用额外的正比于向量大小的空间。我当时直接看的答案,到晚上搜了搜才看懂。

解决方法使用了两个额外的向量,from和to,变量top。如果对i位置进行初始化,进行一下步骤:
from[i] = top; to[top]=i;data[i] = 0;top++;
from[i]=top的目的是将i在to中的索引放入to中,to[top]=i的意识是,这个top位置对应的是i,这时data就可以做相应的操作,然后top右移。
判断一个位置是否初始化过的条件是( from[i] < top && to[ from[i] ] == i ),from[i]

10.类似于取快递,根据电话号码的最后一位或者最后两位进行分类,类似于哈希的思想,用顺序遍历来处理碰撞。不能用开头的原因是很多电话号码的前面都是一样的,比如手机号码都是以1开头的。而且最后一位的分布比较随机、均匀。

11.= =答案竟然说飞鸽传书。

12.铅笔? T.T ....

你可能感兴趣的:(C/C++,算法)