当前位置: 首页 > news >正文

【C++进阶】哈希的应用 --- 布隆过滤器

在这里插入图片描述

👦个人主页:@Weraphael
✍🏻作者简介:目前学习C++和算法
✈️专栏:C++航路
🐋 希望大家多多支持,咱一起进步!😁
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨


目录

  • 一、问题引入
  • 二、布隆过滤器的概念
  • 三、布隆过滤器的实现
      • 3.1 基本结构
      • 3.2 插入
      • 3.3 查找
      • 3.4 删除
      • 3.5 测试
      • 3.6 优化
  • 四、总结
  • 五、代码

一、问题引入

随着玩王者荣耀的用户越来越多,想要取一个心悦的名字是非常难的。当名字重复的时候,系统非常快的提示“名字已被使用”,那么它是如何做到快速查找名字是否被使用了呢?

在这里插入图片描述

在如此大的数据下,首先可以想到使用位图:

  • 但由于位图的数据必须是size_t的,那么需要先将名字(字符串)映射成整型,然后再存入位图中。然而,我们对位图开空间是根据数据范围的,但字符串的长度是可变的,使用位图来表示长度不固定的数据会带来很大的挑战。比如,开少了可能引发冲突,那么就会导致误判。比如说李白和百里都占同一个比特位并且都标记成1,当有人将修改了百里这一名称,那么其实就是reset操作,那么,李白也同样会被reset,那么就会有第二个人可以取李白这个名字。

  • 并且字符串在计算机中是以字符集编码的方式存储的,一个字符可能由一个或多个字节组成。而位图一般用于表示集合中元素的存在与否,对于字符集编码来说,字符的种类和编码范围非常广泛,使用位图来表示所有可能的字符将需要非常大的存储空间,并且不实际。

这时候就需要我们本文中的主角: 布隆过滤器Bloomfilter

二、布隆过滤器的概念

布隆过滤器是由布隆在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询。可以用来告诉你 “某样东西一定不存在或者可能存在”

布隆过滤器是如何做到的呢?

这里举一个小故事:假设布隆有一天要去线下见网友,前提是他不知道网友的任何特征,那怎么办?只能发一个消息问对方今天的穿搭,而网友说今天带了一个黑色的帽子,然而布隆一眼望去,今天穿戴黑色帽子的人也特别的多,于是再次向网友询问更多的特征来过滤掉更多穿搭相识的人。

于是布隆过滤器就是 使用多个哈希函数,将一个数据映射到位图结构中,也就是 一个数据映射位图的多个位置哈希与位图结合,即布隆过滤器)。只有当映射的比特位全为1,则说明字符串存在。

在这里插入图片描述

三、布隆过滤器的实现

3.1 基本结构

既然需要多个哈希函数,这里我只模板中添加三个哈希函数的模板参数,以及待存储的数据类型,不过布隆过滤器最常见存储的类型是字符串,所以可以给一个缺省值。

在这里插入图片描述

显然,这三个 哈希函数 的选择是十分重要的,我们在这里提供三种较为优秀的哈希函数(字符串哈希算法),分别是 BKDRHashAPHash 以及 DJBHash

在这里插入图片描述

struct BKDRHash
{size_t operator()(const string& str){register size_t hash = 0;for  (auto& ch : str){hash = hash * 131 + (size_t)ch;    }return hash;}
};struct APHash
{size_t operator()(const string& str){size_t hash = 0;for (auto e : str){if (((size_t)e & 1) == 0){hash ^= ((hash << 7) ^ (size_t)e ^ (hash >> 3));}else{hash ^= (~((hash << 11) ^ (size_t)e ^ (hash >> 5)));}}return hash;}
};struct DJBHash
{size_t operator()(const string& str){if (str.empty())return 0;size_t hash = 5381;for (auto e : str){hash += (hash << 5) + (size_t)e;}return hash;}
};template<size_t N, class K = string, class Hashfunc1 = BKDRHash, class Hashfunc2 = APHash, class Hashfunc3 = DJBHash>
class bloomfilter
{
public:private:bitset<N> _bt;
};

3.2 插入

步骤:

  • 通过三个哈希函数计算不同的哈希值

  • 最后再调用bitset中的set在位图中标记即可

在这里插入图片描述

3.3 查找

判断在不在也非常简单,我们可以再次计算出三个哈希值,只要它们对应的二进制位上是1,说明要查找的字符串存在,只要有一个为0,说明要查找的字符串一定不存在。

在这里插入图片描述

这里需要注意的是:布隆过滤器判断不在是准确的,判断 是不准确的

比如,“李白“映射了位置0 1 3,”百里“映射了位置3 5 7,虽然这两个字符串不会相互影响,但原本”妲己“不存在位图中,并且通过调用test发现三个位置都是1,那么就会误判存在。

在这里插入图片描述

因此 布隆过滤器并不是非常可靠,那该怎么办呢?有人想到了使用 布隆过滤器 + 数据库 的方式进行双重验证

如果 布隆过滤器 判断字符串不存在,那么就是真的不存在,因为这是绝对准确的;但如果在布隆过滤器中存在,可以去数据库里搜索,再反馈给用户。

3.4 删除

布隆过滤器支持删除吗?其实一般是不支持的。因为支持删除会存在重大问题,删除一个值会影响其他字符串。

在这里插入图片描述

虽然成功删除了 “李白”,但同时也影响了 “百里”,当要验证“百里”是否存在时,会被判断为不存在,所以布隆过滤器,一般是不支持删除操作的。

3.5 测试

在这里插入图片描述

3.6 优化

如果真的误判存在了那该怎么办呢?有的人想增加哈希函数的个数,那么问题来了,增加多少个合适呢?

还有一个比较合适的方案:扩大布隆过滤器的长度,使数据更分散,来降低误判的概率

那么如何选择合适的布隆过滤器的长度呢?对此有大佬做出了研究:

在这里插入图片描述

我们可以来估算一下,假设用3个哈希函数,即K = 3ln2 的值我们取 0.7,那么 mn 的关系大概是 m = n×k/ln2=4.2n ,也就是过滤器长度应该是插入元素个数的 4 -5倍

在这里插入图片描述

四、总结

优点:

  1. 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关

  2. 哈希函数相互之间没有关系,方便硬件并行运算

  3. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势

  4. 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势

  5. 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能

  6. 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

缺点:

  1. 有误判率,不能准确判断元素是否在集合中(补救方法:再建立一个白名单,存储可能会误判的数据)

  2. 不能获取元素本身

  3. 一般情况下不能从布隆过滤器中删除元素

实际应用场景:

  1. 注册时对于 昵称、用户名、手机号的验证

  2. 减少磁盘 IO 或者网络请求,因为一旦一个值必定不存在的话,我们可以不用进行后续昂贵的查询请求

五、代码

本篇博客相关代码:点击跳转

相关文章:

【C++进阶】哈希的应用 --- 布隆过滤器

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…...

Linux——自写一个简易的shell

目录 前言 一、打印提示信息 二、分割字符串 三、替换程序 前言 之前学习了很多进程相关的知识&#xff0c;包括环境变量、进程的创建与退出、进程等待、进程替换。现在可以用所学的作一个小总结&#xff0c;手撕一个shell解释器&#xff0c;大致的思路是先通过环境变量获…...

【操作系统学习笔记】处理器管理1.3

【操作系统学习笔记】处理器管理1.3 参考书籍: 王道考研 视频地址: Bilibili 进程控制 进程控制的主要功能是对系统中的所有进程实施有效的管理&#xff0c;它具有创建新进程、撤销已有进程、实现进程状态转换的功能。简而言之&#xff0c;进程控制就是要实现进程的状态转换…...

AndroidUI--setContentView

我们的Activity通常继承自Activity或者AppCompatActivity&#xff0c;这两个setContentView流程是不同的 一、继承自Activity 1、Activity.setContentView Activity中setContentVIew调用了getWindow().setContentView(view, params); getWindow返回的是mWindow&#xff0c;mWi…...

编程笔记 Golang基础 047 mysql数据库连接与操作

编程笔记 Golang基础 047 mysql数据库连接与操作 一、连接与操作1. 安装MySQL驱动2. 导入驱动包3. 连接数据库4. 执行SQL查询和操作5. 使用连接池6. 处理事务 二、连接字符串三、应用示例四、比较 MySQL凭借其开源、高效、稳定、灵活、安全以及广泛的社区支持等诸多优势&#x…...

.jsonl 格式文件的解释

根据 CHATGPT .jsonl 文件格式是一种文本文件格式&#xff0c;通常用于存储每行一个JSON对象的数据。.jsonl 文件的每一行都是一个独立的JSON对象&#xff0c;这些对象之间没有任何分隔符。 以下是一个示例.jsonl文件的内容&#xff1a; {"name": "John"…...

nodejs web服务器 -- 搭建开发环境

一、配置目录结构 1、使用npm生成package.json&#xff0c;我创建了一个nodejs_network 文件夹&#xff0c;cd到这个文件夹下&#xff0c;执行&#xff1a; npm init -y 其中-y的含义是yes的意思&#xff0c;在init的时候省去了敲回车的步骤&#xff0c;如此就生成了默认的pac…...

laravel-admin 头部添加操作

新建html 样式及js namespace App\Admin\Extensions\Nav;class Links {public function __toString(){return <<<HTML<li><a href"" οnclick"js_method();return false;"><i class"fa fa-floppy-o"></i><s…...

mysql笔记:10. 日志

文章目录 一、日志概述二、错误日志1. 启动2. 查看3. 删除 三、二进制日志1. 启动2. 查看3. 删除 四、通用查询日志1. 启动2. 查看3. 删除 五、慢查询日志1. 启动2. 查看3. 删除 日志是MySQL数据库的重要组成部分&#xff0c;日志文件中记录着MySQL数据库运行期间发生的变化。M…...

代码随想录刷题笔记-Day32

1. 最大子序和 53. 最大子数组和https://leetcode.cn/problems/maximum-subarray/ 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组&#xff1a;是数组中的一个连续…...

指针的学习5

目录 sizeof和strlen的区别 sizeof strlen 数组和指针笔试题解析 一维数组 字符数组 二维数组 指针运算笔试题解析 题目1&#xff1a; 题目2&#xff1a; 题目3&#xff1a; 题目4&#xff1a; 题目5&#xff1a; 题目6&#xff1a; 题目7&#xff1a; sizeof和…...

Dynamo——常用几何形体的创建与编辑(二)

上一次&#xff0c;我们简单整理了一些创建几何形体的节点用法&#xff0c;今天我们接着整理一些&#xff0c;几何形体的编辑方法。 一、坐标点的平移复制 [Point.Add] 使用节点 “Vector.ByCoordinates” 生成一个向量&#xff0c;将该向量连接到 “Point.Add” 节点的输入端 …...

uniapp富文本编辑-editor-vue2-vue3-wangeditor

前言 不管vue2还是vue3&#xff0c;都推荐官方的editor组件, 官方手册 https://uniapp.dcloud.net.cn/component/editor.html除了“微信小程序”&#xff0c;其他小程序想要使用editor组件实现富文本编辑&#xff0c;很难 ​​​​​​​第三方组件wangeditor在vue2&#xff0…...

【java】22:try-catch 异常处理

try-catch 方式处理异常说明 public static void main(String[] args) { int num1 10; int num2 0; try { int res num1 / num2; } catch (Exception e) { System.out.println(e.getMessage()); } } 注意事项 1)如果异常发生了&#xff0c;则异常发生后面的代码不会执行&…...

【C语言】linux内核ip_local_out函数

一、讲解 这个函数 __ip_local_out 是 Linux 内核网络子系统中的函数&#xff0c;部分与本地出口的 IPv4 数据包发送相关。下面讲解这段代码的每一部分&#xff1a; 1. 函数声明 int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)&#xff1a; -…...

动态规划6,最大数组和,环形子数组最大和,乘积最大子数组

最大子数组和 思路&#xff1a; 1.经验题目要求 dp[i]表示&#xff1a;以 i 位置为结尾的所有子数组中的最大和 2.状态转移方程 按长度来划分&#xff0c;如果长度为1&#xff0c;那么dp[i] nums[i]; 如果长度大于1&#xff0c;那么当前位置的最大和就为 i-1 位置最大和 …...

js 清空数组的方法

1、直接赋值空数组 let array [1, 2, 3, 4, 5]; array []; 这种方法并不推荐&#xff0c;如下图所示&#xff1a; 虽然a数组确实变为了空数组&#xff0c;但这种方法只是修改了a的指向&#xff0c;把a指向一个新的空数组&#xff0c;然而[1,2,3,4,5]这个数组并没有被清除&a…...

QT中使用QProcess执行命令,实时获取数据,例如进度条

前言 因为之前写了一个接收和发送文件的脚本&#xff0c;然后又需要获取进度&#xff0c;同步到进度条中。 效果&#xff1a; 使用正则匹配&#xff0c;获取命令行命令中的以下数据&#xff0c;然后同步到进度条 源码demo&#xff1a; 非完整代码&#xff1a; #include <Q…...

绘图设计:用Draw.io绘制图形技巧大全(含统一建模语言UML模板)

一、常见UML模板 1.流程图 2.用例图 include是包含关系&#xff0c;extend是扩展关系 简而言之&#xff0c;include是子集指向父集&#xff1b;而extend是扩展用例指向基础用例&#xff08;基础用例可以理解为系统核心功能&#xff0c;扩展用例是可选的&#xff0c;不是必须…...

被唤醒的“第二十条”深入人心

近来张艺谋执导的电影《第二十条》&#xff0c;因为它与正在召开中的全国两会所发布的《最高人民法院工作报告》联系相当紧密&#xff0c;加之可免费收看&#xff0c;网民便相互转告&#xff0c;于是此信息条目立即冲上了网络热搜榜&#xff0c;观者如潮。因为最高人民法院工作…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...