哈希表——布隆过滤器

news/2024/7/7 21:39:07

哈希表——布隆过滤器

  • 一个问题
  • 应用方面
  • 布隆过滤器实现

我们今天继续来了解哈希表的延伸——布隆过滤器

一个问题

我们之前介绍过了位图,我们将数据进行映射到相应的二进制位上。来帮助我们提高检索的效率。但是我们生活中可不是简简单单存个数字就行了。如果我们要映射的是字符串,那就有点麻烦了。

在这里插入图片描述

其实也可以解决,我们之前不是学过了字符串的哈希算法吗?我们可以把相对应的字符串进行相应的哈希算法,得到的整数值,然后再映射到相应的位置上去。
在这里插入图片描述
看样子问题解决了,但是,假设我现在有一个字符串,经过字符串哈希函数的处理映射之后,发现跟"apple"映射的位置一样的:
在这里插入图片描述
这个时候如果我去检查这个位图,位图的结果就是该字符串存在,但实际上该字符串不存在,只是凑巧"apple"的映射和该字符串的映射产生了哈希碰撞,误判了。

那这该怎么办呢?所以,有一个叫布隆的人想到,既然无法避免冲突,那可不可以把这个冲突的概率降低一点,我们多用几个哈希函数处理,一个字符串映射多个位:
在这里插入图片描述
置于为什会降低,其实也很简单,之前我们只有一个哈希函数进行处理,容易冲突。现在我们有三个哈希函数,就算一个冲突了,其他两个还可以有保障。所以降低了冲突的频率。

但是,布隆过滤器只能降低冲突的频率,不能完全避免冲突。这也是它明显的缺点之一。

应用方面

有的同学就要问了,既然布隆过滤器不能彻底解决问题,那它有什么样的价值呢?其实布隆过滤器最大的优势就是优化效率
大家玩游戏的时候,尤其是一些联网的大型游戏,注册用户时,会经历一个必须的步骤——取用户名

这个时候,为了保障每个玩家的独一无二性,我们的用户名是不允许重名的。所以我们有时候注册用户,取的用户名,会显示该用户名已被注册。

这中间,就有布隆过滤器的功劳。

首先,我们得知道,我们玩家的用户名,是储存在服务器上的:
在这里插入图片描述
如果没有布隆过滤器,我要保证不重名,我只能到服务器上一条一条比对。这样的效率就太低了。
在这里插入图片描述

但是如果我们有一个布隆过滤器,如果该用户名不存在,就直接可以存到服务器上。(因为布隆过滤器不会误判没有在服务器上的用户名)
在这里插入图片描述
但是,如果布隆过滤器返回的是有,就要分两种情况:一是真的存在,二是误判了。
这个时候,我们只能到服务器上去找了。

在这里插入图片描述

布隆过滤器实现

我们来实现一下布隆过滤器:

//BKDR算法
struct BKDRHash
{
	size_t operator()(const string& key)
	{
		// BKDR
		size_t hash = 0;
		for (auto e : key)
		{
			hash *= 31;
			hash += e;
		}

		return hash;
	}
};

//APH算法
struct APHash
{
	size_t operator()(const string& key)
	{
		size_t hash = 0;
		for (size_t i = 0; i < key.size(); i++)
		{
			char ch = key[i];
			if ((i & 1) == 0)
			{
				hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
			}
		}
		return hash;
	}
};

//DJB算法
struct DJBHash
{
	size_t operator()(const string& key)
	{
		size_t hash = 5381;
		for (auto ch : key)
		{
			hash += (hash << 5) + ch;
		}
		return hash;
	}
};


template<size_t N,
	class K = string,
	class HashFunc1 = BKDRHash,
	class HashFunc2 = APHash,
	class HashFunc3 = DJBHash>
class BoolFilter
{
public:
	void Set(const K& key)
	{
		size_t hash1 = HashFunc1()(key) % N;
		size_t hash2 = HashFunc2()(key) % N;
		size_t hash3 = HashFunc3()(key) % N;

		cout << "第一个hash函数的值" << hash1 << endl;
		cout << "第二个hash函数的值" <<hash2 << endl;
		cout << "第三个hash函数的值" <<hash3 << endl << endl;

		_bt.set(hash1);
		_bt.set(hash2);
		_bt.set(hash3);
	}

	bool Test(const K& key)
	{
		// 判断不存在是准确的
		size_t hash1 = HashFunc1()(key) % N;
		if (_bt.check(hash1) == false)
			return false;

		size_t hash2 = HashFunc2()(key) % N;
		if (_bt.check(hash2) == false)
			return false;

		size_t hash3 = HashFunc3()(key) % N;
		if (_bt.check(hash3) == false)
			return false;

		// 存在误判的
		return true;
	}


private:
	My_bitmap::bitmap<N> _bt;
};

我们可以测试一下:

void TestBF1()
{
	BoolFilter<100> bf;
	bf.Set("Lisa");
	bf.Set("Mike");
	bf.Set("孙悟空");
	bf.Set("林黛玉");

	cout << bf.Test("LISA") << endl;
	cout << bf.Test("Lisa") << endl;
	cout << bf.Test("孙悟空") << endl;
	cout << bf.Test("二郎神") << endl;
	cout << bf.Test("林黛玉") << endl;
	cout << bf.Test("太白晶星") << endl;
}

在这里插入图片描述
这里只是布隆过滤器的简单使用,大家可以在网上接着探索布隆过滤器的判错率以及哈希函数的个数该怎样控制,这些都有大佬给出最全面的分析~。


http://lihuaxi.xjx100.cn/news/2040024.html

相关文章

Selenium基于Python web自动化测试框架 -- PO

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

JWT从入门到上天系列第一章:JWT的简介和传统认证流程的对比

&#x1f609;&#x1f609; 欢迎加入我们的学习交流群呀&#xff01; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring、Security、Docker、Grpc、消息中间件、Rpc、SpringCloud等等很多应用和源码级…

『C语言初阶』第四章-指针(3)

1.字符指针变量 在指针的类型中我们知道有一种指针类型为字符指针char*; 一般使用&#xff1a; int main() {char ch w;char* pc &ch;*pc w;return 0; } 还有一种使用方式&#xff1a; int main() {const char* pstr "hello bit.";//这里是吧一个字…

uniapp运动课程健身打卡系统微信小程序

考虑到实际生活中在我来运动管理方面的需要以及对该系统认真的分析,将系统分为小程序端模块和后台管理员模块&#xff0c;权限按管理员和用户这两类涉及用户划分。 (a) 管理员&#xff1b;管理员使用本系统涉到的功能主要有&#xff1a;首页、个人中心、用户管理、课程类别管理…

Linux(六)__设备管理

磁盘管理 Linux磁盘管理好坏管理直接关系到整个系统的性能问题。 磁盘管理_常用命令 df命令 作用&#xff1a;查看已挂载磁盘的总容量、使用容量、剩余容量等&#xff0c;可以不加任何参数&#xff0c;默认是按k为单位显示的。 语法&#xff1a;df [选项] 选项说明&#…

从零开始学习Netty - 学习笔记 - NIO基础 - 网络编程: Selector

4.网络编程 4.1.非阻塞 VS 阻塞 在网络编程中&#xff0c;**阻塞&#xff08;Blocking&#xff09;和非阻塞&#xff08;Non-blocking&#xff09;**是两种不同的编程模型&#xff0c;描述了程序在进行网络通信时的行为方式。 阻塞&#xff08;Blocking&#xff09;&#xff1…

2024.02.21作业

1. 使用多线程完成两个文件的拷贝&#xff0c;第一个线程拷贝前一半&#xff0c;第二个线程拷贝后一半&#xff0c;主线程回收两个线程的资源 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <time.h&g…

token的理解和代码,token是什么?

面试场景&#xff1a; 以前有个学生去面试&#xff0c;公司问他&#xff0c;如果你们公司的接口文档被你的亲戚看到了&#xff0c;会怎么样&#xff1f;会导致什么问题&#xff0c;为了防止这个问题&#xff0c;需要用什么来解决&#xff1f;这个根据学生回忆的写的。 学生当…