面试专栏:布隆过滤器

什么是布隆过滤器

布隆过滤器(Bloom Filter)是一种高效的数据结构,用于判断一个元素是否存在于一个集合中。它利用位数组和多个哈希函数来实现快速的成员查询。

布隆过滤器的核心思想是用一个位数组(通常用二进制位表示)来表示一个集合,初始时所有位都置为0。

然后,对于每个要加入集合的元素,通过多个哈希函数计算出多个哈希值,然后将位数组中对应的位置置为1。

判断一个元素是否存在于集合时,同样使用多个哈希函数计算出对应的哈希值,然后检查位数组中对应的位置是否都为1,如果有任意一个位置为0,则说明该元素不存在于集合中;如果所有位置都为1,则该元素可能存在于集合中(因为有可能发生哈希碰撞),需要进一步查询底层数据结构来确认。

查询碰撞误判问题

碰撞误判问题用一句话说:指的是当布隆过滤器判断一个元素不存在于集合中时,调用判断是否存在方法它可能会返回给你存在。这种情况主要由于哈希碰撞和过滤器容量不足等原因造成的。

以下是导致布隆过滤器重复误判的一些主要原因:

  1. 哈希碰撞:布隆过滤器使用多个哈希函数将一个元素映射到多个位置。在极少数情况下,不同的元素可能会映射到相同的位置,导致误判。
  2. 过滤器容量不足:如果布隆过滤器的容量设置得不够大,会增加误判的可能性。过小的容量可能会导致哈希冲突增多,从而提高误判率。
  3. 删除操作:Redis 的布隆过滤器不支持删除操作。一旦一个元素被添加,就无法从布隆过滤器中删除。如果需要删除,可能会导致一些误判。
  4. 误判率设置不合理:布隆过滤器的误判率是可以通过合适的参数设置进行调节的。如果误判率设置得过高,可能会导致误判问题。
  5. 业务场景要求高准确性:如果业务场景对准确性要求极高,布隆过滤器可能不是最合适的选择,应该考虑其他更准确的数据结构或算法。

用户注册场景布隆过滤器实战

1. 容量如何评估

不管任何业务或者任何技术的容量评估都不会是一拍脑门决定的。

如果淘宝商城第一年做业务时,他们可能很难预估订单量。因为他们不清楚运营会带给他们多少流量以及订单,也没有往年的相关数据参考。这种是比较难评估的。但是咱们 12306 的用户注册场景,明显不在这个范围内。

当面试官问布隆过滤器的大小时,我们可以先说一个容量评估思路。比如:用户注册场景下布隆过滤器的主要评估来源是使用 12306 的用户,从系统刚开始运行就开始估算,大概会有多少用户会注册该平台。

2013年12月8日推出平台,同年国内人口约等于14亿,算上前几年大部分人不会使用系统,再加上国内每年的新增人口数量,估算出一个大概值即可。该题重点在一个解题思路,并不一定需要准备的数值。如果非要说的话,让不使用 12306 的人和未来十年的增长起一个对冲,设置 14 亿即可。意味着 10 年内 14 亿这个数据量不会出问题。

2. 碰撞率如何评估

如果需要选择一个较低的碰撞率目标。通常情况下,布隆过滤器的碰撞率可以设置在非常低的范围内,例如 0.1%或更低。

这从根本上来说是一个空间和重复碰撞的博弈。希望空间占用小,那就尽可能让碰撞率调高。如果希望碰撞率低,那就把空间调大。

布隆过滤器的内存需求可以通过以下公式来计算:

m = -(n * ln(p)) / (ln(2)^2)

其中:

  • m 是所需要的位数。
  • n 是过滤器中元素的数量。
  • p 是期望的误报率。

在给定的条件下,其中 n 是10^9(10亿),p 是0.001(0.1%),我们可以将这些值带入公式中:

m = -(10^9 * ln(0.001)) / (ln(2)^2)

运算后,我们得到的结果 m 大约为 2.88*10^10 位。为了将位转换为字节(1字节 = 8位),我们需要除以8:

m_in_bytes = m / 8

这将得到大约 3.6*10^9 字节,或者说约 3.6 GB 的内存需求。

但是请注意,这是一个理想的估计值。实际上,在实际设备和实现中,布隆过滤器可能需要稍微多一些的内存。例如,Redis 的布隆过滤器插件(如 RedisBloom)可能需要一些额外的内存来维护元数据和内部结构。

3. 初始容量评估不够用怎么办

如果随着国内人口的越来越多,之前评估的布隆过滤器容量不够了怎么办?

我们可以有个定时任务,每天统计已注册人数有多少,和布隆过滤器的预期值差值还有多少。假设布隆过滤器容量设置 14 亿,当已注册人数达到这个数量 80%时,我们通过后台任务重建布隆过滤器,在 14 亿的基础上再增加一定的数量即可。

<think>好的,我现在需要回答用户关于Java算法学习资料和教程的请求。首先,用户提到了几个引用,我需要仔细看看这些引用内容,看看有没有直接相关的资源。引用2、3、4、5似乎都和Java算法学习有关,尤其是引用2和4,提到了数据结构与算法Java版教程以及代码随想录的刷题网站,这可能对用户有帮助。 接下来,用户希望得到学习资料和教程的推荐,所以我应该整理这些引用中的相关信息,并给出结构化的建议。根据引用2,动力节点老师的教程适合新手入门,应该放在推荐的首位。引用4提到的代码随想录网站,可能适合刷题和系统学习算法,这也是一个重点。引用3提到的全栈学习路线中包含算法部分,可以作为长期学习的参考。引用5的《糊涂算法》专栏可能适合面试准备,但需要确认是否有Java版本,因为用户明确提到Java相关的资料。 需要注意的是,引用1和引用3中的部分内容可能更偏向于Java全栈或架构师路线,但用户主要关注算法,所以需要筛选出相关的部分。同时,用户可能对如何系统学习、实战练习和面试准备感兴趣,所以应该分这几个方面来组织回答,每个部分推荐相应的资源。 另外,用户提供的引用中有一些是课程或网站,需要确保链接或资源名称正确,但用户给出的引用中没有具体链接,所以可能需要用名称和描述来引导用户搜索。例如,引用2中的“数据结构与算法Java版学习教程”由动力节点老师录制,用户可以在他们的官方网站或教育平台查找。 最后,生成相关问题时要围绕Java算法学习的不同方面,比如基础学习、实战项目、面试准备等,确保问题有针对性,帮助用户进一步探索。</think>### Java算法学习资料与教程推荐 #### 一、系统化学习路径 1. **数据结构与算法基础(Java版)** - **推荐资源**:动力节点老师的《数据结构与算法Java版学习教程》专为Java程序员设计,内容通俗易懂,涵盖基础数据结构(如链表、树、图)和经典算法(排序、查找、动态规划等)[^2]。 - **学习重点**:从复杂度分析入手,逐步掌握线性表、栈、队列的实现与应用。 2. **算法进阶与实战** - **代码随想录刷题网站**:提供LeetCode题目解析(Java实现),按算法类型分类(如双指针、回溯、贪心),适合系统性刷题训练[^4]。 - **示例代码片段**: ```java // 快速排序Java实现 public void quickSort(int[] arr, int low, int high) { if (low < high) { int pivot = partition(arr, low, high); quickSort(arr, low, pivot - 1); quickSort(arr, pivot + 1, high); } } ``` #### 二、专项学习资源 1. **面试算法强化** - **《糊涂算法》专栏**:针对Java面试高频考点(如字符串处理、二叉树遍历),提供解题模板与优化技巧[^5]。 - **高频题目**:Top K问题、链表反转、二分查找变体等。 2. **全栈学习中的算法模块** - **Java全栈学习路线**:引用3的路线图中包含分布式系统中的算法(如一致性哈希、负载均衡策略),适合拓展工程视角[^3]。 #### 三、学习工具与社区 1. **ACM格式输入训练** - 引用4提到的输入处理技巧,可结合牛客网/力扣平台练习Java的输入输出优化。 2. **开源项目实践** - 参考引用3的分布式系统案例,尝试用Java实现简单Raft算法或布隆过滤器。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Nathaniel333

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

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

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

打赏作者

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

抵扣说明:

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

余额充值