最近开始看《编程珠玑》了,传说中的“看起来很眼熟啊,而过几分钟后又得出结论——以前从来没读过”,刚看了第一章的内容,作者思考问题的方式和角度确实很好,前言提示说不要看太快,习题要一道一道跟着做,自己做过再去看答案。
这一章的内容是磁盘排序的问题,用了位向量优化了排序(其实跟计数排序的原理差不多,就是利用所有的关键字在一定的范围内,而这里的关键字还是没有重复的,弄一个位向量,遇到一个值就将它相应的位置置为1,自然可以有O(n)的做法。不过如果范围太过分散就没办法了,因为浪费的内存太多了)。
下面是我自己实现的位向量的类,感觉挺使用的,效率也高,不过没有做过多的exception的handle(比如申请不到想要的内存之类的),只做了下标范围的检查。
#include <stdio.h>
#include <assert.h>
#include <string>
using namespace std;
class MyBitSet
{
typedef char EType;
static const int SHIFT = 3, MASK = 0x07;
int size;
EType* data;
void calIndex(int index, int& key, int& then) {
key = index >> SHIFT;
then = index & MASK;
}
public:
MyBitSet(int size): size(size) {
int len = (size+sizeof(EType)-1)/sizeof(EType);
data = new EType[len];
for (int i = 0; i < size; ++i)
reset(i);
}
// set the bit to be 0
void reset(int index) {
assert(index >= 0 && index < size);
int key, then;
calIndex(index, key, then);
data[key] &= ~(EType(1) << then);
}
// set the bit to be 1
void set(int index) {
assert(index >= 0 && index < size);
int key, then;
calIndex(index, key, then);
data[key] |= (EType(1) << then);
}
// test the value of the bit
bool test(int index) {
assert(index >= 0 && index < size);
int key, then;
calIndex(index, key, then);
return (data[key] & (EType(1) << then)) > 0;
}
// a shortcut to test the value of the bit
bool operator [] (int index) {
return test(index);
}
// transform the data into a string
string str() {
string ans(size, '0');
for (int i = 0; i < size; ++i)
if (test(i))
ans[i] = '1';
return ans;
}
// display the data
void print() {
printf("%s\n", str().data());
}
};
int main() {
int size = 10;
MyBitSet s(size);
s.print();
for (int i = 0; i < size; ++i) {
s.set(i);
s.print();
s.reset(i);
}
s.set(4);
s.set(5);
s.set(6);
for (int i = 0; i < size; ++i)
if (s[i])
printf("1");
else
printf("0");
printf("\n");
return 0;
}