利用位图可以判断某个数字是否在一个大范围数据中
具体代码如下:
①bit_map.h
#pragma once
#include <stddef.h>
#include <stdint.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);
②bit_map.c
#include "bit_map.h"
#include <stdlib.h>
#include <string.h>
//可以拿65来测试,如果要表示的最大数字是65,则需要2个uint64_t
size_t DataSize(size_t capacity)
{
return capacity / (sizeof(uint64_t)* 8) + 1; //uint64_t在该操作系统编译器下占8个字节
}
void GetOffset(size_t index, size_t* n, size_t* offset)
{
*n = index / (sizeof(uint64_t)* 8);
*offset = index % (sizeof(uint64_t)* 8);
}
//capacity表示容量,即位图能保存的最大位
void BitMapInit(BitMap* bm, size_t capacity)
{
if (bm == NULL)
{
return;
}
bm->capacity = capacity;
size_t size = DataSize(capacity);
bm->data = (uint64_t*)malloc(sizeof(uint64_t) * size);
}
// 把第 index 位置为1
void BitMapSet(BitMap* bm, size_t index)
{
if (bm == NULL)
{
return;
}
if (index >= bm->capacity)
{
return;
}
size_t n, offset; //64个bit位表示一个数,n为数字的下标;offset表示具体的bit位
GetOffset(index, &n, &offset);
bm->data[n] |= (1ul << offset); //将指定位设置为1
//unsigned int 1u
//long 1l
//unsigned long 1ul
}
// 把第 index 位置为0
void BitMapUnset(BitMap* bm, size_t index)
{
if (bm == NULL)
{
return;
}
if (index >= bm->capacity)
{
return;
}
size_t n, offset; //64个bit位表示一个数,n为数字的下标;offset表示具体的bit位
GetOffset(index, &n, &offset);
bm->data[n] &= ~(1ul << offset); //将指定位设置为0
}
// 测试 index 为是 1 , 还是 0. 如果是1, 就返回1. 否则返回0.
int BitMapTest(BitMap* bm, size_t index)
{
if (bm == NULL)
{
return 0;
}
if (index >= bm->capacity)
{
return 0;
}
size_t n, offset;
GetOffset(index, &n, &offset);
//在进行按位操作时,切记注意防止整型溢出
uint64_t ret = bm->data[n] & (1ul << offset);
return ret != 0 ? 1 : 0;
}
// 把整个位图所有的位都设为0.
void BitMapClear(BitMap* bm)
{
if (bm == NULL)
{
return;
}
memset(bm->data, 0, sizeof(uint64_t)*DataSize(bm->capacity));
}
// 把整个位图所有的位都设为1.
void BitMapFill(BitMap* bm)
{
if (bm == NULL)
{
return;
}
memset(bm->data, 0xff, sizeof(uint64_t)*DataSize(bm->capacity));
//一个字节一个字节的设置为1,一个字节对应8个bit位
}
void BitMapDestroy(BitMap* bm)
{
if (bm == NULL)
{
return;
}
bm->capacity = 0;
free(bm->data);
bm->data = NULL;
return;
}
③test.c
#include "bit_map.h"
#include <stdio.h>
#include <windows.h>
#define TEST_HEADER printf("\n\n=======================%s=======================\n",__FUNCTION__)
void TestInit()
{
TEST_HEADER;
BitMap bm;
BitMapInit(&bm, 65);
printf("bm->capacity expect 65,actual %lu\n", bm.capacity);
size_t size = bm.capacity / (sizeof(uint64_t)* 8) + 1;
printf("size expect 2,actual %lu\n", size);
size_t i = 0;
for (; i < bm.capacity / (sizeof(uint64_t)* 8) + 1; ++i)
{
printf("[%lu]:%lx ", i, bm.data[i]);
}
}
void TestSet()
{
TEST_HEADER;
BitMap bm;
BitMapInit(&bm, 127);
BitMapSet(&bm, 63);
size_t i = 0;
for (; i < bm.capacity / (sizeof(uint64_t)* 8) + 1; ++i)
{
printf("[%lu]:%lx ", i, bm.data[i]);
}
}
void TestUnset()
{
TEST_HEADER;
BitMap bm;
BitMapInit(&bm, 127);
BitMapSet(&bm, 63);
BitMapUnset(&bm, 63);
size_t i = 0;
for (; i < bm.capacity / (sizeof(uint64_t)* 8) + 1; ++i)
{
printf("[%lu]:%lx ", i, bm.data[i]);
}
}
void TestBitMapTest()
{
TEST_HEADER;
BitMap bm;
BitMapInit(&bm, 127);
BitMapSet(&bm, 63);
int ret = BitMapTest(&bm, 63);
printf("ret expect 1,actual %d\n", ret);
BitMapUnset(&bm, 63);
ret = BitMapTest(&bm, 63);
printf("ret expect 0,actual %d", ret);
}
void TestClear()
{
TEST_HEADER;
BitMap bm;
BitMapInit(&bm, 127);
BitMapSet(&bm, 63);
BitMapSet(&bm, 1);
BitMapSet(&bm, 2);
BitMapSet(&bm, 64);
BitMapSet(&bm, 65);
BitMapSet(&bm, 31);
size_t i = 0;
for (; i < bm.capacity / (sizeof(uint64_t)* 8) + 1; ++i)
{
printf("[%lu]:%lx ", i, bm.data[i]);
}
printf("\n");
BitMapClear(&bm);
for (i = 0; i < bm.capacity / (sizeof(uint64_t)* 8) + 1; ++i)
{
printf("[%lu]:%lx ", i, bm.data[i]);
}
}
void TestFill()
{
TEST_HEADER;
BitMap bm;
BitMapInit(&bm, 127);
BitMapFill(&bm);
size_t i = 0;
for (; i < bm.capacity / (sizeof(uint64_t)* 8) + 1; ++i)
{
printf("[%lu]:%lx ", i, bm.data[i]);
}
}
void TestDestroy()
{
TEST_HEADER;
BitMap bm;
BitMapInit(&bm, 127);
BitMapSet(&bm, 63);
size_t i = 0;
for (; i < bm.capacity / (sizeof(uint64_t)* 8) + 1; ++i)
{
printf("[%lu]:%lx ", i, bm.data[i]);
}
printf("\n");
printf("[销毁后]:\n");
BitMapDestroy(&bm);
printf("bm->capacity expect 0, actual %lu\n", bm.capacity);
printf("bm->data expect NULL, actual %p\n", bm.data);
}
int main()
{
TestInit();
TestSet();
TestUnset();
TestBitMapTest();
TestClear();
TestFill();
TestDestroy();
system("pause");
return 0;
}
结果为: