解决问题 : 给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中 .
- 当我们遇到这个问题时,可能第一时间会想到哈希搜索, 但是仔细发现 , 当我们使用哈希去解决该问题时 , 就会发现1KB=1024Byte 1MB=1024KB 1G=1024MB 而10亿个Byte大约就是1G , 40亿个Byte大约就是4G , 而题中条件为无符号整数 , 那就是16G , 所以当我们使用哈希搜索去解决该问题时 , 在不考虑哈希冲突和负载因子的时候就需要16G内存去存储40亿个无符号整数 , 到这里你是不是觉得使用哈希搜索解决该问题就有点得不偿失了 ,
- 这里就引进了位图去解决该问题 , 这里可以使用位去标记该元素是否存在 , 1 就代表存在 , 0 就代表不存在 , 一个char有八个bit位这里就只需要500MB的内存就可以处理所有的数据
- 当我们使用位图去解决该问题时 , 就又会出现一些问题 , 那就是元素时如何找到自己的位置 , 所以这里就要介绍一个关于大小端字节序的概念 , 在一般的编译环境中数据存储都为小端存储模式 ( 是指数据的低字节序保存在内存的低地址中, 而数据的高字节序, 保存在内存的高低址中 )
大小端字节序详解 传送门 --- https://blog.csdn.net/ds19980228/article/details/82595184
存储方式如下图所示 :
当我们要去存储该元素时, 只需要将该元素除上8,再模上8, 就能找到自己的位置, 然后将该位置 1 即可
代码如下 :
BitMap . h 文件
#pragma once
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
//数据结构
typedef struct BitMap
{
char * data;
//位图最大能表示的比特位数
size_t capacity;
}BitMap;
//位图的初始化
void BMPInit(BitMap * bmp, size_t capacity);
//位图的销毁
void BMPDestory(BitMap * bmp);
//位图的存储
void BMPInsert(BitMap * bmp, size_t x);
//位图的删除
void BMPResert(BitMap * bmp, size_t x);
//检查元素是否存在
int BMPCheck(BitMap * bmp, size_t x);
//测试
void BMPTest();
BitMap . c 文件
#include "BitMap.h"
//位图的初始化
void BMPInit(BitMap * bmp, size_t capacity)
{
assert(bmp);
//开辟空间,这里加1是为了防止空间开辟不够
//假如值需要三个位,这里加1就能防止内存开辟失败的问题
bmp->data = (char*)malloc(capacity / 8 + 1);
//将所有为置0
memset(bmp->data, 0, capacity / 8 + 1);
//位图最大能表示的比特位数
bmp->capacity = capacity;
}
//位图的销毁
void BMPDestory(BitMap * bmp)
{
assert(bmp);
free(bmp->data);
bmp->data = NULL;
bmp->capacity = 0;
}
//位图的存储
void BMPInsert(BitMap * bmp, size_t x)
{
assert(bmp);
//找到字节位置
int index = x >> 3;
//找到位的位置
int num = x % 8;
//将该位置1
bmp->data[index] |= (1 << num);
}
//位图的删除
void BMPReset(BitMap * bmp, size_t x)
{
assert(bmp);
//找到字节位置
int index = x >> 3;
//找到位的位置
int num = x % 8;
//将该位置0
bmp->data[index] &= ~(1 << num);
}
//检查元素是否存在
//如果存在返回1,不存在返回0
int BMPCheck(BitMap * bmp, size_t x)
{
assert(bmp);
//找到字节位置
int index = x >> 3;
//找到位的位置
int num = x % 8;
return (bmp->data[index] & (1 << num)) == 0 ? 0 : 1;
}
//测试
void BMPTest()
{
BitMap bmp;
BMPInit(&bmp, 4000000000);
BMPInsert(&bmp, 4);
BMPInsert(&bmp, 46);
BMPInsert(&bmp, 3);
BMPInsert(&bmp, 74);
printf("%d\n",BMPCheck(&bmp, 4));
printf("%d\n",BMPCheck(&bmp, 5));
printf("%d\n",BMPCheck(&bmp, 3));
printf("%d\n",BMPCheck(&bmp, 73));
printf("%d\n",BMPCheck(&bmp, 46));
printf("%d\n\n",BMPCheck(&bmp, 9));
BMPReset(&bmp, 74);
printf("%d\n",BMPCheck(&bmp, 74));
printf("%d\n",BMPCheck(&bmp, 2));
BMPDestory(&bmp);
}
Test . c 文件
#include "BitMap.h"
int main()
{
BMPTest();
system("pause");
return 0;
}
调试结果如下 :
若有出错或不懂的地方, 欢迎留言, 共同进步 !