在處理大數據量問題時,用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;
}