C++布隆过滤器BloomFilter的简单实现

C++布隆过滤器BloomFilter的简单实现

1.引言

​ 在谈布隆过滤器之前,我们首先需要知道哈希和位图。哈希,就是映射,位图,就是一个个bit位,一般用来判断在不在的模型。但是位图有一个很致命的缺点是:无法映射字符串等类型,所以引入了布隆过滤器。而布隆过滤器,不仅解决了映射字符串的问题,而且还在哈希上升级了映射规则,不再采用单一映射,而采用多映射原则即判断一个元素在不在是采用多个bit位来控制的。
在这里插入图片描述

​ 那么,具体布隆过滤器是怎么样存放字符串的呢? 现在一种常见的思路是将一个字符串的每个字符的ASCII码加起来代表一个字符串即可,但是相信很多朋友在读到这里的时候肯定心里已经列举了很多反例了。是的,这种哈希规则无法避免具有相同组合阵容的ASCII,于是聪明的大佬想到了对每个字符进行乘以一个31或者131等等之类的数再加起来,这样一来,哪怕具有相同阵容的字符串也会有不一样的ASCII总值了。这就是众多哈希映射规则函数中的BKDR算法了,类似的算法还有很多,它们之所以这么做的原因可能也是参照了一些数学上的研究。我们在此次实现的映射规则上也会至少采用三种哈希算法规则来尽量避免映射冲突。

​ 是的,只能说避免冲突,任何东西都无法保证全部,布隆过滤器也是一样,这也是它最大的缺点之一,就是存在误判。不过布隆过滤器之所以叫过滤器,就是可以当作“过滤器”配合着跟其他场景使用从而达到提高效率的目的。例如:在注册QQ判断QQ昵称的时候,倘若该昵称不存在,那么则一定是不存在的没有其他情况。但是倘若判断存在,则还存在一种误判的场景,即别人占用了你的哈希位,这种可能存在误判情况下也需要结合着数据库来综合判定,从整体而言,效率提升的非常高。

2.实现内容

讲完了原理,那么我们来实现一个最简单的布隆过滤器。

要写之前肯定要准备好我们控制映射规则的哈希仿函数。我们之前提到了BKDR哈希算法就是其中一个,这次我们实现准备了三个,对应着一个元素映射三个bit位。它们分别是:BKDRHash、APHash和DJBHash

2.1哈希仿函数

各个哈希仿函数思路是:

BKDR:每个字符乘以31、131、13131等数字,再相加就不会重复。

AP:将整个字符串视为整体通过一定规则转化为一个中间哈希值,再由中间哈希值来生成最终哈希值就能避免重复。

DJB:它通过对字符串中的每个字符进行一系列的位运算和加法操作来生成哈希值。

struct BKDRHash  //思路是:每个字符乘以31、131、13131等数字,再相加就不会重复
	{
		size_t operator()(const string& s)
		{
			size_t  hash = 0;
			for (auto ch : s)
			{
				hash += ch;
				hash *= 31;
			}
			return hash;
		}
			
	};
	struct APHash//思路:将整个字符串视为整体通过一定规则转化为一个中间哈希值,再由中间哈希值来生成最终哈希值就能避免重复
	{
		size_t operator()(const string& s)
		{
			size_t hash = 0;
			for (long i = 0; i < s.size(); i++)
			{
				size_t ch = s[i];
				if ((i & 1) == 0)
				{
					hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
				}
				else
				{
					hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
				}
			}
			return hash;
		}
	};


	struct DJBHash//思路:它通过对字符串中的每个字符进行一系列的位运算和加法操作来生成哈希值
	{
		size_t operator()(const string& s)
		{
			size_t hash = 5381;
			for (auto ch : s)
			{
				hash += (hash << 5) + ch;
			}
			return hash;
		}
	};

2.2类结构

N代表最多插入key数据的个数 ,K代表数据类型,后面的三个模板参数代表映射规则

实现功能有:set存入函数和test检测是否在的函数

//N代表最多插入key数据的个数 ,K代表数据类型,后面的三个模板参数代表映射规则
	template<size_t N,class K = string,
	class Hash1 = BKDRHash,
	class Hash2 = APHash,
	class Hash3 = DJBHash>
	class BloomFilter
	{
	public:
		void set(const K& key) //设置key值存入
		{}

		bool test(const K& key)//判断key值在不在
		{}


	private:
		bitset<N> _bs;  //底层是位图

	};

2.3set()存入函数

分别设置三个不同哈希函数所对应的哈希值来存入。

void set(const K& key)
		{
			size_t hash1 = Hash1()(key) % N; 
			_bs.set(hash1);

			size_t hash2 = Hash2()(key) % N;
			_bs.set(hash2);

			size_t hash3 = Hash3()(key) % N;
			_bs.set(hash3);
			cout << hash1 << " " << hash2 << " " << hash3 << endl;
		}

2.4test()判断函数

思路是只要有一个位置不在位图中即不在布隆过滤器中。

而且一个值在是不准确的,存在误判 因为可能本来不在的值会被别人已经映射了,导致误判存在了,但是一个值不在一定是准确的

bool test(const K& key)
		{
			size_t hash1 = Hash1()(key) % N;
			if (!_bs.test(hash1)) //但凡有一个位置不在就不在了
			{
				return false;
			}

			size_t hash2 = Hash2()(key) % N;
			if (!_bs.test(hash2))
			{
				return false;
			}

			size_t hash3 = Hash3()(key) % N;
			if (!_bs.test(hash3))
			{
				return false;
			}

			//一个值在是不准确的,存在误判 因为可能本来不在的值会被别人已经映射了,导致误判存在了
			//一个值不在一定是准确的

			return true;
		}

2.5测试

使用以下测试

void test_bloomFilter()
	{
		BloomFilter<100> bs;
		//放入以下四个
		bs.set("sort");
		bs.set("srot");
		bs.set("bloom");
		bs.set("hello world hello Arthur");
		bs.set("world hello Arthur hello ");

		

		cout<<bs.test("tros")<<endl;  //不在
		cout<<bs.test("srot")<<endl;  //在
	}

在这里插入图片描述

可以看到,测试已经成功了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
过滤器(Bloom Filter)是一种重要的数据结构,它用于快速判断一个元素是否存在于一个集合中。过滤器的核心思想是通过一系列哈希函数来对元素进行多次哈希,然后将得到的哈希值映射到一个位数组中,并将对应的位置设为1。当需要判断一个元素是否存在时,同样对其进行多次哈希,检查对应位数组的值是否都为1,若都为1则可以确定元素可能存在;若存在一个0,则可以确定元素一定不存在。因此,过滤器是一种基于概率的数据结构,可以高效地进行查找。 然而,过滤器也存在一些问题。首先,由于多个不同的元素可能会哈希到相同的位上,因此在查询时可能出现误判,即判断一个元素存在时实际上并不存在。这种误判是由于多个元素共享了某一位的原因导致的。其次,过滤器的特性决定了它无法支持元素的删除操作,因为删除一个元素可能会影响其他元素的判断结果,从而增加误判率。 要注意的是,计数过滤器(Counting Bloom Filter)提供了一种实现删除操作的可能性,但并不能保证在后续查询时该值一定返回不存在。因此,不能说计数过滤器支持删除,而是说计数过滤器提供了实现删除的可能。 [3<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【海量数据处理】过滤器BloomFilter](https://blog.csdn.net/qq_43727529/article/details/127180864)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [Java --- redis7之过滤器BloomFilter](https://blog.csdn.net/qq_46093575/article/details/130613434)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Arthur___Cui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值