Chinaunix首页 | 论坛 | 博客
  • 博客访问: 45674
  • 博文数量: 15
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 176
  • 用 户 组: 普通用户
  • 注册时间: 2014-01-31 01:57
个人简介

资深码农

文章分类

全部博文(15)

文章存档

2016年(3)

2014年(12)

我的朋友

分类: C/C++

2014-01-31 02:28:52

最近在学习编程珠玑,其中有一个很经典的例子,是如何使用较小的内存存储数据,介绍了位向量,下面是其实现。

点击(此处)折叠或打开

  1. class IntSetBitVec {
  2.     enum {BITSPERWORD = 32, SHIFT = 5, MASK = 0x1f};
  3.     int n, hi, *x;
  4.     void set(int i) {        x[i>>SHIFT] |= (1<<(i & MASK));}
  5.     void clr(int i) {        x[i>>SHIFT] &= ~(1<<(i & MASK));}
  6.     int test(int i) {return x[i>>SHIFT] & (1<<(i & MASK));}
  7. public:
  8.     IntSetBitVec(int maxelms, int maxval)
  9.     {
  10.         hi = maxval;
  11.         x = new int[1+hi/BITSPERWORD];
  12.         for (int i = 0; i < hi; i++)
  13.         {
  14.             clr(i);
  15.         }
  16.         n = 0;
  17.     }

  18.     int size() {return n;}
  19.     void insert(int t)
  20.     {
  21.         if (test(t))
  22.             return;
  23.         set(t);
  24.         n++;
  25.     }

  26.     void report(int *v)
  27.     {
  28.         int j = 0;
  29.         for (int i = 0; i < hi; i++)
  30.             if (test(i))
  31.                 v[j++] = i;
  32.     }
  33. };
仅仅三十几行代码,却非常经典。IntSetBitVec这个类提供了set,clr,test几个方法,参数i为32位整形,作用是设置、清除以及检测是否包含整数i。不难看出,构造函数IntSetBitVec()根据存储数据的最大值maxval来分配内存,举个例子,如果存储的最大数是100的话,那么分配的内存仅仅是1+100/32 = 4个byte,可以想象,如果用一个new int[100]来分配内存的话,需要占用主存100个字节的空间,相比而言,位向量的做法相当的节省存储空间。
使用测试代码进行测试,平台为VC2010,代码如下,

点击(此处)折叠或打开

  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3.     IntSetBitVec* aSetVec = new IntSetBitVec(32, 31*31*31+1);
  4.     for (int i = 0; i < 32; i++)
  5.         aSetVec->insert(i*i*i);
  6.     int array1[32];
  7.     aSetVec->report(array1);

  8.     for (int i = 0; i < 32; i++)
  9.         cout << array1[i] << " ";
  10.     cout << endl;
  11.     system("pause");
  12.     return 0;
  13. }
上述代码首先分配一个位向量的对象,向位向量对象中插入32个数,分别是0到31的立方,然后将其放如一个长度为32的整形数组中,输出如下,
0 1 8 27 64 125 216 343 512 729 1000 1331 1728 2197 2744 3375 4096 4913 5832 685
9 8000 9261 10648 12167 13824 15625 17576 19683 21952 24389 27000 29791
使用这种测试用例,实际上对于位向量来说是不适合的,因为最大的数是31的立方即29791,而分配的内存空间是29791/32+1 = 931byte,相对来说是非常浪费的,那对于这种i^3的这种输入来说有没有更好的数据机构模型呢,答案是肯定的,那就是使用STL中的SET,代码如下,

点击(此处)折叠或打开

  1. class IntSetSTL {
  2.     set<int> S;
  3. public:
  4.     IntSetSTL(int maxelements, int maxval) { }
  5.     int size() {return S.size(); }
  6.     void report(int* v)
  7.     {
  8.         int j = 0;
  9.         set<int>::iterator i;
  10.         for (i = S.begin(); i != S.end(); ++i)
  11.             v[j++] = *i;
  12.     }
  13. };
代码十分简洁,实际上熟悉SET的同学们应该知道IntSetSTL只是Set的一个简单封装,STL中的Set内部使用红黑树实现,可以达到高效的插入和查找(红黑树非常平衡)。如果要存储的数据是比较稀疏的,取值范围又很大,那么set这种容器非常合适。



阅读(1162) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~