位图操作宏定义先列出来
/* 位图属性变量 */
#define BITMAP_STEP(bitMapType) (sizeof(bitMapType) * 8)
#define BITMAP_STEPNUM(uiMaxKey, step) ((uiMaxKey + step -1) / step)
#define BITMAP_BITNUM(uiMaxKey, step) (((uiMaxKey + step - 1) / step) * step)
/* 增加key到BitMap */
#define ADD_KEY(key, map, step) (map[uiKey/uiStep] |= (1 << (key% step)))
#define ADD_KEY_SHIFT(key,map,step,shift) (map[key>>shift] |= (1<<(key&(step-1))))
/* 删除key从BitMap */
#define DEL_KEY(key, map, step) (pBitMap[key / step] &= (~(1 << (key % step))))
#define DEL_KEY_SHIFT(key,map, step,shift) (map[key>>shift] &= (~(1<<(key&(step- 1)))))
/* 查询key是否在BitMap中 */
#define KEY_EXIST(key, map, step) (map[key / step] & (1 << (key % step)))
#define KEY_EXIST_SHIFT(key,map,step,shift) (map[key>>shift] & (1 << (key & (step- 1))))
正文:
BitMap就是位图, BitMap是个好数据结构, 尤其对大数据行业,搞清楚其原理后,会发现位图很easy.
先给出两个假设
(1)--->假设要处理的都是正整数,(负整数也可以搞定,做下特殊处理就可以,此文章忽略)
(2)--->假设申请位图内存类型为unsigned int
1.BitMap的bit总数有什么决定
bit总数由最大数N确定,而和数队列的长度无关!
比如队列:
que1 = {1,2,3,4,5,6,5,4,3,2,1,2,2,10,3,4,5,6,7,8,6,5,4,3,2,1}
que2= {1,1024}
que1对应的BitMap需要的Bit总数由最大数10确定
que2对应的BitMap需要的Bit总数由最大数1024确定
虽然que1队列很长,que2队列很短,但是que2的BitMap却要大很多~
2.BitMap的bit总数怎么计算?
假设数据集中的最大数为N
如果位图内存类型为U8, 则BitCnt = ((N + 7) / 8) * 8;
如果位图内存类型为U16, 则BitCnt = ((N + 15) / 16) * 16;
如果位图内存类型为U32, 则BitCnt = ((N + 31) / 32 ) * 32;
3.BitMap的U8/U16/U32总数怎么计算?
假设数据集中的最大数为N,
如果位图内存类型为U8, 则U8Cnt = ((N + 7) / 8)
如果位图内存类型为U16, 则U16Cnt = ((N + 15) / 16) ;
如果位图内存类型为U32, 则U32Cnt = ((N + 31) / 32 );
4.在位图BitMap中增加数x
假设数据集中的最大数为N, 且x < N
即数n对应BitMap中的位赋值为1
U32* const uiBitMap = (unsigned int*)malloc(((N + 31) / 32) * 32);
uiBitMap[ x / 32 ] |= 1 << (x % 32);
置1的移位操作公式为:
uiBitMap[ x >> 5 ] |= (1 << ( x & 0x1F)); /* 31的十六进制为0x1F*/
提示:虽然BitMap不是二维数组,但是可以用访问U32类型的二维数组思维来思考如何使用BitMap,这样会很容易理解.
5.查询位图BitMap中是否存在数x
return uiBitMap[ x >> 5] & (1 << (x & 0x1F)); /* 真值则表示x存在,假值则表示x不存在 */
即x对应的bit为1则表示x存在, 如果为0则表示不存在.
6.从BitMap中删除数x
uiBitMap[x >> 5] &= (~(1 << (x % 32)));
即将x对应的bit置0即可.
7. demo代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 位图属性变量 */
#define BITMAP_STEP(bitMapType) (sizeof(bitMapType) * 8)
#define BITMAP_STEPNUM(uiMaxKey, uiStep) ((uiMaxKey + uiStep -1) / uiStep)
#define BITMAP_BITNUM(uiMaxKey, uiStep) (((uiMaxKey + uiStep -1) / uiStep) * uiStep)
/* 增加key到BitMap */
#define BITMAP_ADD_KEY(uiKey, pBitMap, uiStep) (pBitMap[uiKey / uiStep] |= (1 << (uiKey % uiStep)))
#define BITMAP_ADD_KEY_SHIFT(uiKey, pBitMap, uiStep, uiShiftN) (pBitMap[uiKey >> uiShiftN] |= (1 << (uiKey & (uiStep - 1))))
/* 删除key从BitMap */
#define BITMAP_DEL_KEY(uiKey, pBitMap, uiStep) (pBitMap[uiKey / uiStep] &= (~(1 << (uiKey % uiStep))))
#define BITMAP_DEL_KEY_SHIFT(uiKey, pBitMap, uiStep, uiShiftN) (pBitMap[uiKey >> uiShiftN] &= (~(1 << (uiKey & (uiStep - 1)))))
/* 查询key是否在BitMap中 */
#define BITMAP_KEY_EXIST(uiKey, pBitMap, uiStep) (pBitMap[uiKey / uiStep] & (1 << (uiKey % uiStep)))
#define BITMAP_KEY_EXIST_SHIFT(uiKey, pBitMap, uiStep, uiShiftN) (pBitMap[uiKey >> uiShiftN] & (1 << (uiKey & (uiStep - 1))))
int main()
{
/* 数据集 */
unsigned int auiQue[] = {1,2,3,4,5,6,7,8,9,6,5,4,2,3,4,1};
/* 找到最大数N */
unsigned int uiMaxN = 0;
unsigned int* puiNEnd = auiQue + sizeof(auiQue) / sizeof(unsigned int);
unsigned int* puiN = NULL;
for (puiN = auiQue; puiN < puiNEnd; ++puiN)
{
if (*puiN > uiMaxN)
uiMaxN = *puiN;
}
/* 申请BitMap内存 */
const unsigned int uiStep = BITMAP_STEP(unsigned char);
const unsigned int uiShiftN = 3;
const unsigned int uiU8Cnt = BITMAP_STEPNUM(uiMaxN, uiStep);
const unsigned int uiBitCnt = BITMAP_BITNUM(uiMaxN, uiStep);
unsigned char* pu8BitMap = (unsigned char*)malloc(uiBitCnt);
/* 初始化BitMap */
memset(pu8BitMap, 0, uiBitCnt);
/* 按照数据集每个值的真假值添加到BitMap中 */
/* 假设6,9的二值属性为真,请将6,9增加到BitMap中 */
printf("\nAdd key 6, 9 to BitMap......");
unsigned int uiX = 6;
BITMAP_ADD_KEY(uiX, pu8BitMap, uiStep);
uiX = 9;
BITMAP_ADD_KEY_SHIFT(uiX, pu8BitMap, uiStep, uiShiftN);
/* 打印增加6,9后的BitMap */
printf("\n\ndump bit flag map:\n");
for (uiX = 0; uiX < uiBitCnt; ++uiX)
{
if (BITMAP_KEY_EXIST(uiX, pu8BitMap, uiStep))
printf("%d ", 1);
else
printf("%d ", 0);
}
printf("\n\ndump <key, flag> map:\n");
for (uiX = 0; uiX < uiBitCnt; ++uiX)
{
if (BITMAP_KEY_EXIST_SHIFT(uiX, pu8BitMap, uiStep, uiShiftN))
printf("<%u,%d>\t", uiX, 1);
else
printf("<%u,%d>\t", uiX, 0);
if (uiX % uiStep == (uiStep - 1))
printf("\n");
}
/* 查询0,6,7,8,9是否在BitMap中 */
printf("\nkey:0,6,7,8,9 is in BitMap?:");
unsigned int auiQuery[] = {0,6,7,8,9};
puiNEnd = auiQuery + sizeof(auiQuery) / sizeof(unsigned int);
for (puiN = auiQuery; puiN < puiNEnd; ++puiN)
{
uiX = *puiN;
if (BITMAP_KEY_EXIST_SHIFT(uiX, pu8BitMap, uiStep, uiShiftN))
printf("(value, isInBitMap):(%u, %s)\n", *puiN, "Yes");
else
printf("(value, isInBitMap):(%u, %s)\n", *puiN, "No");
}
/* 删除6,9俩key从BitMap */
printf("\nDelete key 6, 9 from BitMap.");
uiX = 6;
BITMAP_DEL_KEY(uiX, pu8BitMap, uiStep);
uiX = 9;
BITMAP_DEL_KEY_SHIFT(uiX, pu8BitMap, uiStep, uiShiftN);
printf("\nIs key:{0,6,7,8,9} in BitMap?:");
puiNEnd = auiQuery + sizeof(auiQuery) / sizeof(unsigned int);
for (puiN = auiQuery; puiN < puiNEnd; ++puiN)
{
uiX = *puiN;
if (BITMAP_KEY_EXIST_SHIFT(uiX, pu8BitMap, uiStep, uiShiftN))
printf("(value, isInBitMap):(%u, %s)\n", *puiN, "Yes");
else
printf("(value, isInBitMap):(%u, %s)\n", *puiN, "No");
}
printf("\ndump bit flag map:\n");
for (uiX = 0; uiX < uiBitCnt; ++uiX)
{
if (BITMAP_KEY_EXIST(uiX, pu8BitMap, uiStep))
printf("%d ", 1);
else
printf("%d ", 0);
}
return 0;
}
8. 运行结果:
<完>