news 2026/4/3 4:11:06

数据结构:布隆过滤器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数据结构:布隆过滤器

数据结构:布隆过滤器

布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,由霍华德·布隆在1970年提出,用于快速判断一个元素是否存在于一个集合中。它的核心特点是存在误判的可能,但不存在漏判,即:

  • 若判断元素“不存在”,则一定不存在;
  • 若判断元素“存在”,则可能存在(存在一定的误判率);
  • 支持高效的插入查询操作,且不支持删除元素(普通布隆过滤器)。

资料:https://pan.quark.cn/s/43d906ddfa1bhttps://pan.quark.cn/s/90ad8fba8347https://pan.quark.cn/s/d9d72152d3cf

一、布隆过滤器的核心原理

布隆过滤器的底层依赖二进制位数组多个独立的哈希函数,核心流程如下:

1. 初始化

  • 申请一个长度为m的二进制位数组(初始值全为0);
  • 选择k个独立的哈希函数h₁, h₂, ..., h_k,每个哈希函数能将输入元素映射到[0, m-1]范围内的一个整数索引。

2. 插入元素

对于要插入的元素x

  1. 依次通过k个哈希函数计算,得到k个索引值h₁(x), h₂(x), ..., h_k(x)
  2. 将二进制位数组中这k个索引对应的位置置为1

3. 查询元素

对于要查询的元素y

  1. 依次通过k个哈希函数计算,得到k个索引值h₁(y), h₂(y), ..., h_k(y)
  2. 检查位数组中这k个索引对应的位置:
    • 所有位置都是1→ 判定元素y可能存在(存在误判);
    • 任意一个位置是0→ 判定元素y一定不存在

核心特性解释

  • 误判原因:不同元素通过哈希函数计算后,可能会映射到相同的索引位置,导致“哈希冲突”。当一个不存在的元素的k个哈希索引恰好都被其他元素置为1时,就会误判为“存在”。
  • 无漏判原因:只有元素确实插入过,其k个哈希索引才会全部置1;若有一个位置为0,则元素一定没插入过。

二、关键参数与误判率计算

布隆过滤器的性能由三个核心参数决定:

  1. 二进制位数组长度m:位数组越长,误判率越低,但空间占用越高;
  2. 哈希函数个数k:哈希函数越多,误判率越低,但插入和查询的时间复杂度越高;
  3. 集合中预期元素个数n:即布隆过滤器需要存储的元素总数。

误判率公式

布隆过滤器的理论误判率P计算公式为:
P=(1−e−knm)k P = \left(1 - e^{-\frac{kn}{m}}\right)^kP=(1emkn)k
其中e是自然对数的底数。

参数选择最优解

为了最小化误判率P,哈希函数个数k的最优值为:
k=mnln⁡2≈0.693⋅mn k = \frac{m}{n} \ln 2 \approx 0.693 \cdot \frac{m}{n}k=nmln20.693nm
此时的最小误判率为:
Pmin=(12)k=e−k2nm P_{min} = \left(\frac{1}{2}\right)^k = e^{-\frac{k^2 n}{m}}Pmin=(21)k=emk2n

例如:若预期存储n=100000个元素,要求误判率P≤0.01%,则可计算出m≈1917000(约 235KB),k≈13

三、布隆过滤器的实现示例(Python)

importmathimporthashlibclassBloomFilter:def__init__(self,expected_n,error_rate=0.01):""" 初始化布隆过滤器 :param expected_n: 预期存储的元素个数 :param error_rate: 允许的最大误判率 """# 计算二进制位数组长度 mself.m=self._calculate_m(expected_n,error_rate)# 计算最优哈希函数个数 kself.k=self._calculate_k(expected_n,self.m)# 初始化二进制位数组(用整数模拟,bitarray 更高效,这里用列表简化)self.bit_array=[0]*self.m# 哈希函数列表(使用 hashlib 实现多个独立哈希)self.hash_seeds=[iforiinrange(self.k)]def_calculate_m(self,n,p):"""计算位数组长度 m"""m=-(n*math.log(p))/(math.log(2)**2)returnint(math.ceil(m))def_calculate_k(self,n,m):"""计算最优哈希函数个数 k"""k=(m/n)*math.log(2)returnint(math.ceil(k))def_hash(self,value,seed):"""单个哈希函数:将 value 映射到 [0, m-1] 索引"""# 使用 MD5 哈希,结合种子生成不同的哈希值md5=hashlib.md5((str(value)+str(seed)).encode('utf-8'))# 将哈希结果转为整数,取模得到索引returnint(md5.hexdigest(),16)%self.mdefadd(self,value):"""插入元素 value"""forseedinself.hash_seeds:idx=self._hash(value,seed)self.bit_array[idx]=1defcontains(self,value):"""查询元素 value 是否存在"""forseedinself.hash_seeds:idx=self._hash(value,seed)ifself.bit_array[idx]==0:returnFalsereturnTrue# 使用示例if__name__=="__main__":# 预期存储 10000 个元素,误判率 1%bf=BloomFilter(expected_n=10000,error_rate=0.01)# 插入元素test_set=[f"element_{i}"foriinrange(10000)]forelemintest_set:bf.add(elem)# 测试存在的元素(应返回 True)print(bf.contains("element_123"))# True# 测试不存在的元素(大概率返回 False,小概率误判为 True)print(bf.contains("nonexistent_element"))# False(或 True,误判)# 输出参数print(f"位数组长度 m:{bf.m}")print(f"哈希函数个数 k:{bf.k}")

四、布隆过滤器的特性

1. 优点

  • 空间效率极高:相比哈希表、红黑树等结构,布隆过滤器仅用二进制位数组存储,空间复杂度为O(m),远低于其他结构;
  • 时间效率高:插入和查询的时间复杂度均为O(k)k为哈希函数个数,通常是常数),效率极高;
  • 支持并行操作:哈希函数之间相互独立,插入和查询可并行执行;
  • 无数据存储:布隆过滤器不存储元素本身,仅存储二进制位,适合敏感数据场景(如密码黑名单)。

2. 缺点

  • 存在误判率:无法 100% 准确判断元素存在,误判率与mkn相关;
  • 不支持删除操作:普通布隆过滤器删除元素会导致误判率升高(多个元素共享同一组二进制位);
  • 无法获取元素本身:布隆过滤器仅记录“存在性”,无法存储元素的额外信息。

3. 改进方案

  • 计数布隆过滤器:将二进制位数组改为计数器数组(每个位置存储整数),插入时计数器加 1,删除时减 1,解决删除问题,但空间占用更高;
  • 分层布隆过滤器:将多个布隆过滤器分层,用于处理动态数据集,降低误判率;
  • 布隆过滤器联盟:多个布隆过滤器协同工作,适用于分布式系统。

五、布隆过滤器的典型应用

  1. 缓存穿透防护

    • 场景:Redis 缓存中,若查询一个不存在的 key,请求会穿透到数据库,导致数据库压力过大;
    • 方案:用布隆过滤器存储所有缓存的 key,查询前先通过布隆过滤器判断 key 是否存在,不存在则直接返回,避免穿透。
  2. 黑名单过滤

    • 场景:垃圾邮件过滤、恶意 IP 拦截、违禁词检测;
    • 方案:将黑名单中的元素存入布隆过滤器,快速判断新元素是否在黑名单中。
  3. 分布式系统去重

    • 场景:分布式爬虫去重、分布式任务调度去重;
    • 方案:多个节点共享一个布隆过滤器,判断任务/URL 是否已被处理,避免重复执行。
  4. 数据库查询优化

    • 场景:判断一个值是否存在于数据库的大表中;
    • 方案:将大表的主键存入布隆过滤器,查询前先判断,不存在则直接返回,减少数据库查询次数。
  5. 网络爬虫 URL 去重

    • 场景:爬虫爬取 URL 时,避免重复爬取相同页面;
    • 方案:用布隆过滤器存储已爬取的 URL,新 URL 先查询布隆过滤器,存在则跳过。

六、布隆过滤器与其他数据结构的对比

数据结构空间复杂度插入时间复杂度查询时间复杂度支持删除误判率适用场景
布隆过滤器O(m)O(k)O(k)不支持(普通版)海量数据的存在性判断
哈希表O(n)O(1)(平均)O(1)(平均)支持需存储元素及额外信息
红黑树O(n)O(log n)O(log n)支持有序数据的增删改查
位图(BitMap)O(m)O(1)O(1)支持整数集合的存在性判断(无哈希冲突)

布隆过滤器的核心优势是极致的空间效率,适合“允许少量误判、不支持删除、仅需存在性判断”的场景;若需精确判断或存储元素信息,则需选择哈希表等结构。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/27 16:04:49

C语言字符串

文章目录 字符串基本概念定义和初始化字符串输入输出如下格式均可实现输入输出 字符串遍历操作字符串和字符指针字符指针的赋值引用 通用的字符串处理函数输入输出复制 连接 比较 求长度链接比较长度查找替换 字符串 基本概念 1.C语言字符串本质就是数组的延伸,以…

作者头像 李华
网站建设 2026/3/21 6:10:32

7大核心技术突破:WebRL-Llama-3.1-8B如何重塑智能浏览器交互新范式

你是否曾为重复性的网页操作感到疲惫?每天花数小时在不同网站间切换、点击、填写表单,却发现自己真正有价值的思考时间被严重挤压?在数字化信息爆炸的今天,传统浏览器操作模式已经成为制约工作效率的关键瓶颈。而WebRL-Llama-3.1-…

作者头像 李华
网站建设 2026/3/29 16:06:29

litemall开源电商系统:10分钟搭建你的专属商城平台

litemall开源电商系统:10分钟搭建你的专属商城平台 【免费下载链接】litemall linlinjava/litemall: LiTmall 是一个基于Spring Boot MyBatis的轻量级Java商城系统,适合中小型电商项目作为基础框架,便于快速搭建电子商务平台。 项目地址: …

作者头像 李华
网站建设 2026/3/12 17:15:50

防腐涂料哪家好

防腐涂料哪家好,海洋涂料脱颖而出在工业和建筑等众多领域,防腐涂料的应用极为广泛,它能有效保护物体表面免受腐蚀侵害,延长其使用寿命。然而,面对市场上琳琅满目的防腐涂料品牌,许多人都会发出“防腐涂料哪…

作者头像 李华
网站建设 2026/4/1 2:54:17

【计算机毕业设计案例】基于SpringBoot北京市公交管理系统的设计与实现基于JAVA的北京市公交管理系统(程序+文档+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/3/29 8:33:38

ThingsGateway:重新定义工业物联网边缘网关的下一代解决方案

ThingsGateway:重新定义工业物联网边缘网关的下一代解决方案 【免费下载链接】ThingsGateway ThingsGateway 是基于Net6/7/8的跨平台边缘采集网关,提供底层PLC通讯库,通讯调试软件等。 项目地址: https://gitcode.com/gh_mirrors/th/Things…

作者头像 李华