“《编程珠玑》(第2版)第1章”:课后习题

  1. 如果不缺内存,如何使用一个具有库的语言来实现一种排序算法表示和排序集合?

  1)可以使用C语言中的快速排序qsort(参考自cplusplus),具体代码如下:

 1 /* qsort example */
 2 #include <stdio.h>      /* printf */
 3 #include <stdlib.h>     /* qsort */
 4 
 5 int values[] = { 40, 10, 100, 90, 20, 25 };
 6 
 7 int compare(const void * a, const void * b)
 8 {
 9     return (*(int*)a - *(int*)b);
10 }
11 
12 int main()
13 {
14     int n;
15     qsort(values, 6, sizeof(int), compare);
16     for (n = 0; n < 6; n++)
17         printf("%d ", values[n]);
18     return 0;
19 }
qsort

  关于qsort,有一篇博文写的不错,可以参考。

  2)可以使用C++标准模板库函数sort(参考自cplusplus),具体代码如下:

 1 // sort algorithm example
 2 #include <iostream>     // std::cout
 3 #include <algorithm>    // std::sort
 4 #include <vector>       // std::vector
 5 
 6 bool myfunction(int i, int j) { return (i < j); }
 7 
 8 struct myclass {
 9     bool operator() (int i, int j) { return (i < j); }
10 } myobject;
11 
12 int main() {
13     int myints[] = { 32, 71, 12, 45, 26, 80, 53, 33 };
14     std::vector<int> myvector(myints, myints + 8);               // 32 71 12 45 26 80 53 33
15 
16     // using default comparison (operator <):
17     std::sort(myvector.begin(), myvector.begin() + 4);           //(12 32 45 71)26 80 53 33
18 
19     // using function as comp
20     std::sort(myvector.begin() + 4, myvector.end(), myfunction); // 12 32 45 71(26 33 53 80)
21 
22     // using object as comp
23     std::sort(myvector.begin(), myvector.end(), myobject);        //(12 26 32 33 45 53 71 80)
24 
25     // print out content:
26     std::cout << "myvector contains:";
27     for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
28         std::cout << ' ' << *it;
29     std::cout << '\n';
30 
31     return 0;
32 }
sort

  3)可以利用C++标准模板库容器set来完成相同的功能:

  摘自一篇博文对set容器的简介:实现了红黑树的平衡二叉检索树的数据结构,插入元素时,它会自动调整二叉树的排列,把元素放到适当的位置,以保证每个子树根节点键值大于左子树所有节点的键值,小于右子树所有节点的键值;另外,还得保证根节点左子树的高度与右子树高度相等。可以使用中序遍历(用迭代器)将键值按照从小到大遍历出来。

  关于set容器更详细的介绍请参照cplusplus

  具体代码如下:

 1 #include <iostream>
 2 #include <set>
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     int myints[] = { 65, 23, 75, 42, 13 };
 8     set<int> myset(myints, myints + 5);    // use 'set' member function 'insert' is also ok.
 9 
10     set<int>::iterator itr = myset.begin();
11     for (; itr != myset.end(); itr++)
12     {
13         cout << *itr << " ";    // 13, 23, 42, 65, 75
14     }
15 
16     return 0;
17 }
set

    2. 如何使用位逻辑运算(如与、或、移位)来实现位向量?

  请参考自上上篇博文

    3. 请参考自该题参考答案(P230)

  4. 如果认真考虑了问题3,你将会面对生成小于n且没有重复的m个整数的问题。最简单的方法就是使用前k个正整数。这个极端的数据集合将不会明显地改变位图方法的运行时间,但是可能会歪曲系统排序的运行时间。如何生成位于0至n-1之间的m个不同的随机顺序的随机整数?尽量使你的程序简短且高效。

   对于该题,本书的第12章有比较详细的解答。下边一一列出:

  假设我们有一个能返回很大的随机整数(远大于m和n)的函数bigrand(),以及一个能返回i..j范围内均匀选择的随机整数的函数randint(i, j)。

  1)如果要从r个剩下的整数中选出s个,我们以概率s/r选择下一个数。具体代码如下:

 1 void genknuth(int m, int n)
 2 {
 3     for (int i = 0; i < n; i++)
 4     {
 5         // select m of remaining n-i
 6         if ((bigrand() % (n-i)) < m)
 7         {
 8             cout << i << endl;
 9             m--;
10         }
11     }
12 }
View Code

  2)在一个初始为空的集合里面插入随机整数,直到个数足够。伪代码如下:

1 initialize set S to empty
2 size = 0
3 while size < m do
4     t = bigrand() % n 
5     if t is not in S 
6         insert t into S 
7         size++
8 print the elements of S in sorted order
View Code

  3)用C++标准模板库容器set完成。具体代码如下:

 1 void gensets(int m, int n)
 2 {
 3     // repeated elements are not allowed in set
 4     set<int> S;
 5     while (S.size() < m)
 6         S.insert(bigrand() % n);
 7 
 8     set<int>::iterator itr;
 9     for (itr = S.begin(); itr != S.end(); itr++)
10         cout << *itr << endl;
11 
12 }
View Code

  4)将包含整数0~n-1的数组顺序打乱,然后将前m个元素排序输出。伪代码如下:

1 for i = [0, n)
2     swap(i, randint(i, n-1))
View Code

  5)只打乱该数组的前m个元素。具体代码如下:

 1 void genshuf(int m, int n)
 2 {
 3     int i, j;
 4     int * x = new int[n];
 5     for (i = 0; i < n; i++)
 6         x[i] = i;
 7 
 8     for (i = 0; i < m; i++)
 9     {
10         j = randint(i, n - 1);
11         int t = x[i];
12         x[i] = x[j];
13         x[j] = t;
14     }
15 
16     sort(x, x + m);
17     for (i = 0; i < m, i++)
18         cout << x[i] << endl;
19 
20     delete[] x;
21 }
View Code

   5. 那个程序员说他有1MB的可用存储空间,但是我们概要描述的代码需要1.25MB的空间。他可以毫不费力地索取到额外的空间。如果1MB空间是严格的边界,你会推荐他如何处理呢?你的算法的运行时间又是多少呢?

  使用位图表示1000万个数需要1000万个位,或者说125万个字节。考虑到没有以数字0或1打头的电话号码,我们可以将内存需求降低为100万个字节。另一种做法是采用两趟算法,首先使用5 000 000/8=625 000个字节的存储空间来排序0~4 999 999之间的整数(通过判断归入该范围),然后在第二趟排序5 000 000~9 999 999的整数。k趟算法可以在kn的时间开销和n/k的空间开销内完成对最多n个小于n的无重复正整数的排序。

  6. 如果那个程序员说的不是每个整数最多出现一次,而是每个整数最多出现10次,你又如何建议他呢?你的解决方案如何随着可用存储空间总量的变化而变化?

   如果每个整数最多出现10次,那么我们就可以用4位的半字节来统计它出现的次数。

  

posted @ 2015-03-20 21:29  峰子_仰望阳光  阅读(527)  评论(0编辑  收藏  举报