【性能优化】BitMap的使用:(1)创建BitMap (2)插入key到BitMap (3)删除key到BitMap (4)查询key是否存在于BitMap中

版权声明:本文为博主原创文章,未经博主允许不得转载,转载请注明文章来源,联系方式:[email protected] https://blog.csdn.net/u012421852/article/details/87901858

位图操作宏定义先列出来

/* 位图属性变量  */
#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. 运行结果:

<完>

猜你喜欢

转载自blog.csdn.net/u012421852/article/details/87901858