位图和布隆过滤器

位图和布隆过滤器

当我们对于搜索结构有一定的认识后,我们知道了当我们需要搜索一个数据时,可以二分查找,当让这是较为原始的查找方式,进一步我们掌握了二叉树,学会了利用搜索树查找,可是当数据量为100亿时,我们不可能通过排序然后搜索树查找,进一步我们学会了除了排序的另一种方式映射,从而掌握了哈希查找,可是当数据为100亿时,可能所有的整数都出现了一遍,这意味着我们要开42亿9千万个int空间来存储,大约有16GB大小,这又太过于浪费空间。于是我们想出新的办法来解决问题。

位图

一般来说数据量足够大时,只需要判定存在与否即可,那一个位置仅仅需要存在与不存在两种状态即可,针对这点我们想出了通过位来节省空间保存数据,一个字节的每一个位都表示了一个数据的存在状态,这样的话一个int可以有32个状态,我们保存所有的整数范围仅仅需要512MB即可,大大的节省了空间。
我们可以用下图进一步说明位图的情况:
这里写图片描述
首先我们先需要确定需要存储数据的范围,例如我们一共需要35个数据存储,那么一个int可以表示32个状态,我们开两个int即可。找到所表示数据的状态时先找到他在第几个int例如我们在35个存储数据中找12,首先确定他在第一个int,然后他在第12个位置,更进一步说他在第二个字节的第四个位置,我们再操纵位运算更改状态即可。

接下来我们给出具体的实现方法:
首先定义位图的结构体,并且在初始化中给位图开空间

typedef struct BitMap
{
	size_t* _bits;
	size_t _range;
}BitMap;

void BitMapInit(BitMap* bm, size_t range)
{
	bm->_bits = (size_t*)malloc(sizeof(size_t)*((range>>5)+1));
	bm->_range = range;
	memset(bm->_bits,0, sizeof(rsize_t)*((range >> 5) + 1));
}

接下来这两个接口表示我们需要在第x个位置将状态置为存在与不存在,按照前文所说找到位置操纵位运算即可。

void BitMapSet(BitMap* bm, size_t x)
{
	size_t index = bm->_range/x;
	int num =  bm->_range%x;
	bm->_bits[index] |= (1 << num);
}
void BitMapReset(BitMap* bm, size_t x)
{
	size_t index = bm->_range / x;
	int num = bm->_range%x;
	bm->_bits[index] &= ~(1<<num);
} 

有的时候我们还需要查看某些位置的状态,依旧是操纵位元算即可

int BitMapTest(BitMap* bm, size_t x)
{
	size_t index = bm->_range / x;
	int num = bm->_range%x;
	if ((bm->_bits[index] >> num) & 1 == 1)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

布隆过滤器

位图可以节省空间存储更多的值,可是他只能局限在整数范围内,因为整数是有范围的,再多的数我们也可以用512MB搞定,可是如果我们给的是字符串呢,字符串是没有范围的,无穷无尽的,这个时候我们需要布隆过滤器,布隆过滤器每一个位置用来表示字符串的存在状态,我们也不用次次开512MB空间,因为没有意义了,我们只需要开字符串需要的空间即可,可是又有了新的问题,字符串哈希算法是将字符串转变成整数的算法,然而字符串是无穷的,整数是有穷的,这样就会有很多不同的字符串结果通过该算法转变成的整数值相等,当我们想要找到A字符串时会找到B字符串,而当我们想要插入C字符串时发现已经存在A字符串等很多问题,于是我们想出了新的办法,我们可以通过三种映射方式来映射,每一个字符串在这个位图中给他三个位置,若插入这个字符串那计算得到的三个位置皆赋1,毕竟两个字符串之间三个映射位置全相等的概率基本为0.这样就要求我们开更多的空间,经过研究表明,我们开位图的4.5倍空间最为合适。
接下来给出布隆过滤器的接口实现:
首先定义结构体,初始化这个布隆过滤器并且定义三种映射方式

#include"BitMap.h"
typedef const char* KeyType;

typedef size_t (*HASH_FUNC)(KeyType str);
HASH_FUNC _hashfunc1(KeyType str)
{
	size_t seed = 13;
	 size_t hash = 0;
	while (*str)
	{
		hash = hash * seed + (*str++);
	}
	return (HASH_FUNC)(hash & 0x7FFFFFFF);
}
HASH_FUNC _hashfunc2(KeyType str)
{
	size_t seed = 131;
	size_t hash = 0;
	while (*str)
	{
		hash = hash * seed + (*str++);
	}
	return (HASH_FUNC)(hash & 0x7FFFFFFF);
}
HASH_FUNC _hashfunc3(KeyType str)
{
	size_t seed = 1313;
	size_t hash = 0;
	while (*str)
	{
		hash = hash * seed + (*str++);
	}
	return (HASH_FUNC)(hash & 0x7FFFFFFF);
}

typedef struct BloomFilter
{
	BitMap _bm;
	HASH_FUNC _hashfunc1;
	HASH_FUNC _hashfunc2;
	HASH_FUNC _hashfunc3;
}BloomFilter;

void BloomFilterInit(BloomFilter* bf, size_t range)
{
	BitMapInit(&bf->_bm,range*4);
}

通过操纵位元算给布隆过滤器赋状态

{
	size_t index = bf->_hashfunc1(key)/bf->_bm._range;
	int num = bf->_hashfunc1(key) % bf->_bm._range;
	bf->_bm._bits[index] |= (1 << num);

	size_t index = bf->_hashfunc2(key) / bf->_bm._range;
	int num = bf->_hashfunc2(key) % bf->_bm._range;
	bf->_bm._bits[index] |= (1 << num);

	size_t index = bf->_hashfunc3(key) / bf->_bm._range;
	int num = bf->_hashfunc3(key) % bf->_bm._range;
	bf->_bm._bits[index] |= (1 << num);
}

由于布隆过滤器有三个映射位置,删除的话将会影响其他字符串的存储,所以布隆过滤器没有删除。
找到该字符串是否存在:看三个映射位置的状态是否都为1

int BloomFilterTest(BloomFilter* bf, KeyType key)
{
	size_t index = bf->_hashfunc1(key) / bf->_bm._range;
	int num = bf->_hashfunc1(key) % bf->_bm._range;
	int i = (bf->_bm._bits[index] >> num) & 1;

	size_t index = bf->_hashfunc2(key) / bf->_bm._range;
	int num = bf->_hashfunc2(key) % bf->_bm._range;
	int j = (bf->_bm._bits[index] >> num) & 1;

	size_t index = bf->_hashfunc3(key) / bf->_bm._range;
	int num = bf->_hashfunc3(key) % bf->_bm._range;
	int k = (bf->_bm._bits[index] >> num) & 1;
	if (i + j + k == 3)
	{
		return 0;
	}
	else
	{
		return -1;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值