了解过哈希表,我们接下来看一看哈希表的变形—–位图。
位图:顾名思义就是以bit位为单位,但是需要注意的是我们的位图并不能存储我们的数据,而是借用这样一个结构标记某一个数据是否存在。
如图所示,如果该数据存在,则就将该位图中的相应位从0置为1。
下面我们来实现一下位图的基本操作:
//以下为bit_map.h文件内容
#pragma once
#include
#define BitmapDataType uint64_t
typedef struct Bitmap
{
BitmapDataType *data;
BitmapDataType capacity;//位图最多能够容纳的个数
}Bitmap;
//初始化
void BitmapInit(Bitmap *bm,uint64_t capacity);
//销毁
void BitmapDestroy(Bitmap *bm);
//判断某一位是否为1
int BitmapTest(Bitmap *bm,uint64_t index);
//设置某一位为1
void BitmapSet(Bitmap *bm,uint64_t index);
//设置某一位为0
void BitmapUnset(Bitmap *bm,uint64_t index);
//将位图全部位置为1
void BitmapFill(Bitmap *bm);
//将位图全部位置为0
void BitmapClear(Bitmap *bm);
//初始化
void BitmapInit(Bitmap *bm,uint64_t capacity)
{
if(bm == NULL)
{
//非法输入
return;
}
//capacity:指定位图最多能够容纳多少位
//此处我们使用的uint64_t占8个字节,64位
//比如:capacity=100,应该容纳2个元素才能有足够的位表示100位
//比如:capacity=200,应该容纳4个元素才能有足够的位表示200位
//比如:capacity=300,应该容纳5个元素才能有足够的位表示300位
//比如:capacity=N,N/(sizeof(uint64_t)*8)+1
bm->capacity = capacity;
//size表示我们申请内存时对应的数组元素个数
uint64_t size = capacity/(sizeof(uint64_t)*8)+1;
bm->data = \
(BitmapDataType*)malloc(sizeof(BitmapDataType)*size);
memset(bm->data,0,sizeof(BitmapDataType)*size);
return;
}
//测试一下
void TestInit()
{
Test_Header;
Bitmap bm;
BitmapInit(&bm,100);
printf("expected bm->capacity = 100,\
actual bm->capacity = %lu\n",bm.capacity);
}
//销毁
void BitmapDestroy(Bitmap *bm)
{
if(bm == NULL)
{
//非法输入
return;
}
bm->capacity = 0;
free(bm->data);
return;
}
//此处判断某一位是否为1的函数可用于后面的函数的测试
//辅助函数
void GetOffset(uint64_t index,uint64_t *n,uint64_t *offset)
{
//n是数组中的哪一个元素
*n = index/(sizeof(BitmapDataType)*8);
//offset是该元素中的bit位中的哪一位
*offset = index%(sizeof(BitmapDataType)*8);
return;
}
//检测某一位是否为1,返回1表示该位为1,返回0表示该位为0
int BitmapTest(Bitmap *bm,uint64_t index)
{
if(bm == NULL || index >= bm->capacity)
{
//非法输入
return 0;
}
uint64_t n,offset;
//找到需要判断的位置对应于我们数组中的哪一个元素的哪一位
GetOffset(index,&n,&offset);
//先将1左移offset位,结束以后相应位即为1
//再将其与对应的数组中的元素按位与
//0和1与为0,1和1与为1
//按位与运算完毕就可以知道相应位是否为1
uint64_t ret = bm->data[n] & (0x1ul << offset);
return ret > 0 ? 1:0;
}
//将某一位设置为1
void BitmapSet(Bitmap *bm,uint64_t index)
{
if(bm == NULL || index >= bm->capacity)
{
//非法输入
return;
}
uint64_t n,offset;
//找到需要判断的位置对应于我们数组中的哪一个元素的哪一位
GetOffset(index,&n,&offset);
//将1左移offset位,移动结束以后,需要设置的位置即为1,其余位置为0
//再将其与数组中对应的元素按位或
//0和1或是1,1和1或是1
//有这样的规则,按位或就不会影响其他位的状态
bm->data[n] |= (0x1ul << offset);
}
//将某一位设置为0
void BitmapUnset(Bitmap *bm,uint64_t index)
{
if(bm == NULL || index >= bm->capacity)
{
//非法输入
return;
}
uint64_t n,offset;
//找到需要判断的位置对应于我们数组中的哪一个元素的哪一位
GetOffset(index,&n,&offset);
//先将1左移offset位,那么相应位变为1其余位为0
//再取反,则相应位为0,其余位为1
//在将该结果与对应的数组元素进行按位与
//1和0与结果为0,0和0与结果为0(达到将某一位置为0的效果)
//有这样的规则,则我们的按位与操作不会影响其他的位的状态
bm->data[n] &= ~(0x1ul << offset);
}
//测试一下
void TestSetAndUnset()
{
Test_Header;
Bitmap bm;
BitmapInit(&bm,100);
printf("[将位图某一位置为1函数测试结果]\n");
//将第二位设置为1
BitmapSet(&bm,2);
//非法测试,将第100为设置为1
BitmapSet(&bm,100);
int ret1 = BitmapTest(&bm,2);
int ret2 = BitmapTest(&bm,100);
printf("expected ret1 = 1,actual ret1 = %d\n",ret1);
printf("expected ret2 = 0,actual ret2 = %d\n",ret2);
printf("[将位图某一位置为0函数测试结果]\n");
//将第二位设置为0
BitmapUnset(&bm,2);
//非法测试,将第100位设置为0
BitmapUnset(&bm,100);
int ret3 = BitmapTest(&bm,2);
int ret4 = BitmapTest(&bm,100);
printf("expected ret3 = 0,actual ret3 = %d\n",ret3);
printf("expected ret4 = 0,actual ret4 = %d\n",ret4);
}
//将位图全部置为1
void BitmapFill(Bitmap *bm)
{
if(bm == NULL)
{
//非法输入
return;
}
uint64_t size = bm->capacity/(sizeof(BitmapDataType)*8)+1;
memset(bm->data,0xff,sizeof(BitmapDataType)*size);
}
//将位图全部置为0
void BitmapClear(Bitmap *bm)
{
if(bm == NULL)
{
//非法输入
return;
}
uint64_t size = bm->capacity/(sizeof(BitmapDataType)*8)+1;
memset(bm->data,0x0,sizeof(BitmapDataType)*size);
}
//测试一下
void TestClearAndFill()
{
Test_Header;
Bitmap bm;
BitmapInit(&bm,100);
printf("[将位图全部置为1函数测试结果]\n");
//将位图全部置为1函数测试
BitmapFill(&bm);
int ret1 = BitmapTest(&bm,50);
printf("expected ret1 = 1,actual ret1 = %d\n",ret1);
ret1 = BitmapTest(&bm,0);
printf("expected ret1 = 1,actual ret1 = %d\n",ret1);
ret1 = BitmapTest(&bm,99);
printf("expected ret1 = 1,actual ret1 = %d\n",ret1);
printf("[将位图全部置为0函数测试结果]\n");
//将位图全部清0函数测试
BitmapClear(&bm);
int ret2 = BitmapTest(&bm,50);
printf("expected ret2 = 0,actual ret2 = %d\n",ret2);
ret2 = BitmapTest(&bm,0);
printf("expected ret2 = 0,actual ret2 = %d\n",ret2);
ret2 = BitmapTest(&bm,99);
printf("expected ret2 = 0,actual ret2 = %d\n",ret2);
}