在处理大数据量问题时,用BitSet做标记处理,可以节约内存空间。BitSet的中文翻译有位图、位集、位域等,个人觉得位图比较合适,下文中将以位图作为BitSet的名称。
实现位图的基本思想是,分配一块连续的内存空间,对每一个字节(BYTE)采用位运算设置其中每个位(BIT)的值(0或者1)。下面以位图的C源码说明具体的实现方式。
一、数据结构
typedef struct BitSetStruct BitSet;
struct BitSetStruct {
char *_mblock; // a block of memmery
int _len; //the number of bits in specified by users
int _len2;//the number of bytes in the _mblock
int _count; //the number of bits that is set to 1 in the _mblock
};
其中:
_mblock是一块动态分配的连续内存块。
_len是可自定义的位(BIT)的数目。
_len2为_mblock实际分配的字节(BYTE)数。
_count为被设置为1的位的个数。
二、函数集
BitSet *bitset_new(int bitsCount); //构造函数,bitsCount对应_len,即指定的位数。
BitSet *bitset_new2(const char *bits); //构造函数,以0/1字符串构造位图,如bitset_new2("10101110")。
void bitset_free(BitSet *bs); //析构函数,释放内存空间。
int bitset_size(BitSet *bs); //返回位数, 对应_len的值。
int bitset_count(BitSet *bs); //返回设置为1的位数,对应_count。
void bitset_set_all(BitSet *bs); //将所有位设置为1。
void bitset_reset_all(BitSet *bs); 将所有位设置为0。
void bitset_reset(BitSet *bs, int pos); 将位图中的第pos位设置为0(pos从0开始)。
void bitset_set(BitSet *bs, int pos); 将位图中的第pos设置为1(pos从0开始)。
int bitset_isset(BitSet *bs, int pos); 判断位图中的第pos位是否为1(同样,pos从0开始)。如果该位为1,则返回1;否则返回0。
void bitset_print(BitSet *bs); 输出位图中的每个位的内容。
char *bitset_to_str(BitSet *bs); 将位图转化为字符串,返回的指针需要free。
三、重要的常量
#define BITS_PER_CHAR 8 每个CHAR(对应一个BYTE)的位数。
static const unsigned char mask1[8] =
{
0x01, /* 00000001 */
0x02, /* 00000010 */
0x04, /* 00000100 */
0x08, /* 00001000 */
0x10, /* 00010000 */
0x20, /* 00100000 */
0x40, /* 01000000 */
0x80 /* 10000000 */
};
位运算的掩码,ch |= mask1[i]可以将ch的第i为设置为1, ch &mars[i]可以判断ch的第i位是否为1。
static const unsigned char mask2[8] =
{
0xFE, /* 11111110 */
0xFD, /* 11111101 */
0xFB, /* 11111011 */
0xF7, /* 11110111 */
0xEF, /* 11101111 */
0xDF, /* 11011111 */
0xBF, /* 10111111 */
0x7F /* 01111111 */
};
位运算掩码,ch &=mask2[i]可以将第i位设置为0
源代码有三个文件,使用VC++6.0编译。其中,bitset.h是数据结构和函数声明,bitset.c是函数的实现,main.c是测试文件,可以看到,在代码的设计上我们采用了基于对象的编程思想。
/*
* File: bitset.h
* Purpose: implementation of bitset in C
* Author: puresky
* Date: 2011/05/03
*/
#ifndef _BIT_SET_H
#define _BIT_SET_H
#define BITS_PER_CHAR 8
typedef struct BitSetStruct BitSet;
struct BitSetStruct
{
char *_mblock; // a block of memmery
int _len; //the number of bits specified by users
int _len2;//the number of bytes in the _mblock
int _count; //the number of bits that is set to 1 in the _mblock
};
BitSet *bitset_new(int bitsCount);
BitSet *bitset_new2(const char *bits);
void bitset_free(BitSet *bs);
int bitset_size(BitSet *bs);
int bitset_count(BitSet *bs);
void bitset_reset(BitSet *bs, int pos);
void bitset_reset_all(BitSet *bs);
void bitset_set(BitSet *bs, int pos);
void bitset_set_all(BitSet *bs);
void bitset_reset(BitSet *bs, int pos);
int bitset_isset(BitSet *bs, int pos);
void bitset_print(BitSet *bs);
char *bitset_to_str(BitSet *bs);
#endif
/*
* File: bitset.c
* Purpose: implementation of bitset in C
* Author: puresky
* Date: 2011/05/03
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bitset.h"
static const unsigned char mask1[8] =
{
0x01, /* 00000001 */
0x02, /* 00000010 */
0x04, /* 00000100 */
0x08, /* 00001000 */
0x10, /* 00010000 */
0x20, /* 00100000 */
0x40, /* 01000000 */
0x80 /* 10000000 */
};
static const unsigned char mask2[8] =
{
0xFE, /* 11111110 */
0xFD, /* 11111101 */
0xFB, /* 11111011 */
0xF7, /* 11110111 */
0xEF, /* 11101111 */
0xDF, /* 11011111 */
0xBF, /* 10111111 */
0x7F /* 01111111 */
};
BitSet *bitset_new(int bitsCount)
{
BitSet *bs = (BitSet *)malloc(sizeof(BitSet));
bs->_count = 0;
bs->_len = bitsCount;
// the real length of _mblock is (bitsCount / BITS_PER_CHAR + 1) in Byte
bs->_len2 = bs->_len / BITS_PER_CHAR + 1;
bs->_mblock = (char *)malloc(sizeof(char) * bs->_len2);
memset(bs->_mblock, 0, sizeof(char) * bs->_len2);
return bs;
}
BitSet *bitset_new2(const char *bits)
{
int i, len;
BitSet *bs;
len = strlen(bits);
bs = bitset_new(len);
for(i = 0; i < len; ++i)
if(bits[i] == '1')
bitset_reset(bs, i);
return bs;
}
void bitset_free(BitSet *bs)
{
if(bs)
{
free(bs->_mblock);
free(bs);
}
}
int bitset_size(BitSet *bs)
{
return bs->_len;
}
int bitset_count(BitSet *bs)
{
return bs->_count;
}
void bitset_reset_all(BitSet *bs)
{
memset(bs->_mblock, 0x00, bs->_len2);
bs->_count = 0;
}
void bitset_reset(BitSet *bs, int pos)
{
int i, j;
if(pos >= bs->_len)
{
fprintf(stderr, "bit postion :%d is invalid!\n", pos);
return;
}
i = pos / BITS_PER_CHAR;
j = pos - i * BITS_PER_CHAR;
if(bitset_isset(bs, pos))
{
bs->_mblock[i] &= mask2[j];
bs->_count--;
}
}
void bitset_set_all(BitSet *bs)
{
memset(bs->_mblock, 0xFF, bs->_len2);
bs->_count = bs->_len;
}
void bitset_set(BitSet *bs, int pos)
{
int i, j;
if(pos >= bs->_len)
{
fprintf(stderr, "bit postion :%d is invalid!\n", pos);
return;
}
i = pos / BITS_PER_CHAR;
j = pos - i * BITS_PER_CHAR;
if(!bitset_isset(bs, pos))
{
bs->_count++;
bs->_mblock[i] |= mask1[j];
}
}
int bitset_isset(BitSet *bs, int pos)
{
int i, j;
if(pos >= bs->_len)
{
fprintf(stderr, "bit postion :%d is invalid!\n", pos);
return 0;
}
i = pos / BITS_PER_CHAR;
j = pos - i * BITS_PER_CHAR;
if(bs->_mblock[i] & mask1[j])
return 1;
return 0;
}
void bitset_print(BitSet *bs)
{
int i;
for(i = 0; i < bs->_len; ++i)
printf("%c", (bitset_isset(bs, i) ? '1' : '0'));
printf("\n");
}
char *bitset_to_str(BitSet *bs)
{
int i;
char *str = (char *)malloc(sizeof(char) * (bs->_len + 1));
memset(str, 0, sizeof(char) * (bs->_len + 1));
for(i = 0; i < bs->_len; ++i)
str[i] = (bitset_isset(bs, i) ? '1' : '0');
return str;
}
/*
* File: main.c
* Purpose: testing bitset in C
* Author: puresky
* Date: 2011/05/03
*/
#include <stdio.h>
#include <stdlib.h>
#include "bitset.h"
int main(int argc, char **argv)
{
char *str;
int n;
BitSet *bs = bitset_new(101);
// 1. bitset_set_all
bitset_set_all(bs);
bitset_print(bs);
// 2. bitset_reset_all
bitset_reset_all(bs);
bitset_print(bs);
// 3. bitset_set
bitset_set(bs, 80);
bitset_set(bs, 90);
bitset_set(bs, 30);
bitset_set(bs, 0);
bitset_set(bs, 100);
bitset_print(bs);
// 4.bitset_reset
bitset_reset(bs, 90);
bitset_reset(bs, 100);
bitset_print(bs);
// 5. bitset_count
n = bitset_count(bs);
printf("count:%d\n", n);
// 6. bitset_isset
printf("%d\n", bitset_isset(bs, 80));
printf("%d\n", bitset_isset(bs, 90));
// 7. bitset_to_str
str = bitset_to_str(bs);
printf("str:%s\n", str);
free(str);
bitset_free(bs);
system("pause");
return 0;
}