数据结构--哈希变形 ( 位图 )

解决问题 : 给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;
}

调试结果如下 : 

若有出错或不懂的地方,​ 欢迎留言, 共同进步 !

猜你喜欢

转载自blog.csdn.net/ds19980228/article/details/82592294