位图数据结构,就是用一块内存区域的每个比特表示一个对象的数据结构。
叫做 bitmap 或者 bitplane。
优点是速度快,内存空间占用小,能表示大范围的数据。
《Programming Pearls》里面举了一个例子,假设要对0到一千万范围内的、没有重复元素的正整数排序,
则利用位图数据结构很合适。
要使用位图数据结构,就必须熟悉位操作。
以下是已经写好的操作位图数据结构的实用函数:
#define BITS_PER_BYTE 8
#define BITS_PER_INT (BITS_PER_BYTE * 4)
// set the bit of the int specified by index to 1.
// the index is zero-based, counting from the left(the higher end)
inline void pearl_int_set(int* data, int index)
{
int mask = 1 << (BITS_PER_INT - 1 - index);
*data |= mask;
}
// test whether a bit of the int specified by index is 1.
// the index is zero-based, counting from the left(the higher end)
inline int pearl_int_test(int* data, int index)
{
int mask = 1 << (BITS_PER_INT - 1 - index);
return (*data) & mask;
}
// set a bit of the int specified by bit_index to 0.
// the index is zero-based, counting from the left(the higher end)
inline void pearl_int_clear(int *data, int bit_index)
{
int mask = ~(1 << (BITS_PER_INT - 1 - bit_index));
*data &= mask;
}
// get the right(lower) part of the int.
inline int pearl_int_right(int *data, int count)
{
int mask = 1;
while(count > 0) {
mask = mask << 1 + 1;
}
return *data & mask;
}
// get the left(upper) part of the int value
inline int pearl_int_left(int *data, int count)
{
int mask = 1;
count = BITS_PER_BYTE - count;
while (count > 0) {
mask = mask << 1 + 1;
}
mask = ~mask;
return *data & mask;
}
// set a bit of the speicified memory area to 1.
// @warning this function does NOT perform error checking.
inline void pearl_set(int *bitplane, int index)
{
int offset = index / BITS_PER_INT;
int pos = index - offset * BITS_PER_INT;
pearl_int_set(bitplane + offset, pos);
}
// set a bit of the specified memory area to 0.
// @warning this function does NOT perform error checking.
inline void pearl_clear(int *bitplane, int index)
{
int offset = index / BITS_PER_INT;
int pos = index - offset * BITS_PER_INT;
pearl_int_clear(bitplane + offset, pos);
}
// test if a bit of the specified memory area is 1.
// @warning this function does NOT perform error checking.
inline int pearl_test(int *bitplane, int index)
{
int offset = index / BITS_PER_INT;
int pos = index - offset * BITS_PER_INT;
return pearl_int_test(bitplane + offset, pos);
}
约定:
所有比特的编号方法是,从低字节的高位比特位开始,第一个bit为0,最后一个bit为 n-1。
例如,假设 int arr[4] 表示一块内存区域,共16个字节,共128个比特,第1个整数 arr[0] 的高比特(从左边数,第1个字节,第1个比特)为第0个比特。
因此,上面程序与机器是大端还是小端模式无关。
图解:
编号: |0123456------->-------
|00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 |....
|<-------------------arr[0]--------------------------->|<---------------arr[1]--------------------------------->....
int main(int argc, char* argv[]) {
int* bitplane = (int*)malloc(sizeof(int)*SIZE);
pearl_set(bitplane, n); // 0 <= n <= SIZE * 4 * 8 - 1
if ( pearl_test(bitplane, n) ) {
printf("bit(%d) is set\n", n);
}
pearl_clear(bitplane, n);
if ( pearl_test(bitplane, n) ) {
printf("bit(%d) is cleared\n", n);
}
return 0;
}