在哈希表中,是用一个数组对一个集合进行存储,用于查询查找,在存储时需要将元素的值以及相关信息都要存储进去,就是将其整个结构体都存储与数组的一个位置中。但有时候并不需要知道那么多关于该元素的信息,只是想知道在这个集合中是否存在有某一个元素。这时候据需要使用位图了。
位图也时候一种基本的数据结构,位图是与哈希表有一些联系的,功能上是有一定的相同之处。是将哈希表中用于存储的数组变为了一个二进制位,一个二进制位为一个单位,用于存储信息。我们都知道二进制位的值只有两种可能,一个是 1 另一个就是 0 ,所以我们就可以规定 1 是当前位置为有效位,0 就表示当前位置没有意义。当然我们也可以反过来,只要规定者自己使用时清楚就可以了。这样就有了关于位图的一些操作
bitmap.h
#pragma once
#include<stdio.h>
#include<stddef.h>
#include<stdint.h>
#include<string.h>
#include<stdlib.h>
typedef struct BitMap {
uint64_t* data;
size_t capacity; // max bit
} BitMap;
void BitMapInit(BitMap* bm, size_t capacity);
// 把第 index 位置为1
void BitMapSet(BitMap* bm, size_t index);
// 把第 index 位置为0
void BitMapUnSet(BitMap* bm, size_t index);
// 测试 index 为是 1 , 还是 0. 如果是1, 就返回1. 否则返回0.
int BitMapTest(BitMap* bm, size_t index);
// 把整个位图所有的位都设为1.
void BitMapFill(BitMap* bm);
// 把整个位图所有的位都设为0.
void BitMapClear(BitMap* bm);
void BitMapDestroy(BitMap* bm);
用一个uint64变量表示无符号64位整型变量,这个便于代码的移植性。位图中每一个元素都是uint64。
bitmap.c
#include"bitmap.h"
//用于得到当前位图的元素个数。
size_t GetSize(size_t capacity)
{
return capacity / (8 * sizeof(uint64_t)) + 1;
}
//位图的初始化
//用malooc对位图进行开空间。得到一个数组。
void BitMapInit(BitMap* bm, size_t capacity)
{
if (bm == NULL)
return;
bm->data = (uint64_t*)malloc(8 * GetSize(capacity));
bm->capacity = capacity;
}
//求得需要查找的元素位于数组中的哪个元素,元素中的哪一位
void GetOffset(size_t index, size_t* n, size_t* offset)
{
//n 为第几个uint,offset为在这个uint中第几位
*n = index / (sizeof(uint64_t)* 8);
*offset = index % (sizeof(uint64_t)* 8);
}
//将给定位置的二进制位置1.
void BitMapSet(BitMap* bm, size_t index)
{
if (bm == NULL)
return;
if (index >= bm->capacity)
return;
size_t n;
size_t offset;
GetOffset(index, &n, &offset);
uint64_t ret = 1;
ret <<=offset;
bm->data[n] |= ret;
}
//将给定位置置0
void BitMapUnSet(BitMap* bm, size_t index)
{
if(bm==NULL)
return;
if(index>=bm->capacity)
return;
uint64_t ret=0xFFFFFFFFFFFFFFFF;
size_t n=0;
size_t offset=0;
GetOffset(index,&n,&offset);
ret^=(1ul<<offset);
bm->data[n]&=ret;
//bm->data[n] &= ~(1ul << offset);以上两句可以替换为这个,
}
//测试当前位置为0还是为1.
int BitMapTest(BitMap* bm, size_t index)
{
if(bm==NULL)
return -1;
if(index>=bm->capacity)
return -1;
size_t n=0;
size_t offset=0;
GetOffset(index,&n,&offset);
//int ret = (bm->data[n]&(1ul<<offset));
//return ret != 0 ? 1 : 0;
uint64_t tmp;
tmp = bm->data[n];
tmp>>=offset;
tmp &= 1;
if(tmp==0)
return 0;
else
return 1;
}
//把所有位都设置为1
void BitMapClear(BitMap* bm)
{
if(bm==NULL)
return;
memset(bm->data,0,GetSize(bm->capacity)*sizeof(uint64_t));
}
void BitMapFill(BitMap* bm)
{
if(bm==NULL)
return;
memset(bm->data,0xFF,GetSize(bm->capacity)*sizeof(uint64_t));
}
//销毁整个位图
//因为之前初始化的时候有用malloc申请空间
//所以现在需要用free释放空间
void BitMapDestroy(BitMap* bm)
{
if(NULL == bm)
return;
free(bm->data);
bm->capacity=0;
bm = NULL;
}
test.c
#define __TESTHEAD__
printf("-------------------------------------------
%s--------------------------------------------\n",__FUNCTION__);
void TestInit()
{
BitMap bm;
size_t capacity = 1000;
BitMapInit(&bm, capacity);
printf("capacity: expect 1000 expect %lu", bm.capacity);
}
void TestBitMapSet()
{
__TESTHEAD__;
BitMap bm;
BitMapInit(&bm,150);
BitMapSet(&bm,20);
size_t i=0;
for(;i<GetSize(bm.capacity);i++)
{
printf("[%lu]:%lu",i,bm.data[i]);
}
printf("\n");
}
void TestBitMapUnSet()
{
__TESTHEAD__;
BitMap bm;
BitMapInit(&bm,150);
BitMapUnSet(&bm,20);
size_t i;
for(i=0;i<GetSize(bm.capacity);i++)
{
printf("[%lu]:%lu",i,bm.data[i]);
}
printf("\n");
}
void TestBitMapTest()
{
__TESTHEAD__;
BitMap bm;
BitMapInit(&bm,150);
BitMapSet(&bm,20);
int ret = BitMapTest(&bm,20);
int ret1 = BitMapTest(&bm,110);
printf("expect 1 ,actual %d\n",ret);
printf("expect 0 ,actual %d\n",ret1);
}
void TestBitMapClear()
{
__TESTHEAD__;
BitMap bm;
BitMapInit(&bm,150);
BitMapSet(&bm,20);
BitMapSet(&bm,125);
size_t i;
for(i=0;i<GetSize(bm.capacity);i++)
{
printf("[%lu]:%lu",i,bm.data[i]);
}
printf("\n");
BitMapClear(&bm);
for(i=0;i<GetSize(bm.capacity);i++)
{
printf("[%lu]:%lu",i,bm.data[i]);
}
printf("\n");
}
void TestBitMapFill()
{
__TESTHEAD__;
BitMap bm;
BitMapInit(&bm,150);
BitMapSet(&bm,20);
BitMapSet(&bm,125);
size_t i;
for(i=0;i<GetSize(bm.capacity);i++)
{
printf("[%lu]:%lx",i,bm.data[i]);
}
printf("\n");
BitMapFill(&bm);
for(i=0;i<GetSize(bm.capacity);i++)
{
printf("[%lu]:%lx",i,bm.data[i]);
}
printf("\n");
}
void TestBitMapDestroy()
{
__TESTHEAD__;
BitMap bm;
BitMapInit(&bm,150);
BitMapSet(&bm,20);
BitMapSet(&bm,125);
size_t i;
for(i=0;i<GetSize(bm.capacity);i++)
{
printf("[%lu]:%lx",i,bm.data[i]);
}
printf("\n");
BitMapDestroy(&bm);
printf("capacity expect : 0 actual : %lu\n",bm.capacity);
}
void test()
{
TestInit();
TestBitMapSet();
TestBitMapUnSet();
TestBitMapTest();
TestBitMapClear();
TestBitMapFill();
TestBitMapDestroy();
}
int main()
{
test();
return 0;
}
测试结果