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

位图与布隆过滤器

前言

在前面两个章节中我们详细讲解了哈希表的实现,今天我们就来看一看哈希的应用,也就是位图与布隆过滤器。我将与题目相结合来分别实现这两种应用。

位图

题目

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。
本题中数据量太大,把数据遍历一遍时间消耗太大了,存入红黑树或者哈希表中数据太大,在存储时会消耗GB级内存,这种实现方式不够优秀。
有一种方法可以解决此问题,判断数在不在,说明他有两种状态,而在计算机中刚好可以用0 1来表示这两种状态,再仔细想想一个整型int,四个字节,有32个比特位,每个比特位不是0就是1,刚好能满足这个条件。
假设我们有N个数需要查询且 最大数字为N,现在我们只需要开 N/32+1个int大小类型的空间即可,再把每个数字 映射到位图中,如果 存在就把该比特位 设为1,不存在为0。相比最上面的方法,极大的压缩了空间,下面我来画图给大家解释一下。

 比如说有一个数33,该如何考虑存放呢?

1.首先应该先找到在这个数组的第几个整形中。

2.找到在这个整形的第几位。

这类似于进制问题,找到在第几个整形,只需要用33/32,得到1,也就是下标为一的整形

找到在第几位只需要33%32便查到了在第几位。

这就是 33的位置,通过这个例子,我们知道每一个数字都能一一对应一个比特位,这样我们就能准确找到该位置,判断是0还是1来确定存不存在。现在的问题就是如何让那个比特位变成0或者1,通常我们都采用逻辑与和逻辑或来实现。

1.将该位置变为1:


 

我们只需要将此位置与1进行或等,其余部分为0即可,该如何实现呢?其实也很简单,前面我们算出了他在第几个比特位,如在第j位,现在我们只需要将该位置所的整形或等上(1<<j)便可以实现该位置为1,其他位置保持不变。

2.将该位置变为0:

要想让此位置变成0,我们只需要将此位置与0进行与运算,其他位置全为1,不影响其他位,具体方法是将该位置所的整形与等上~(1<<j)。


依照上面的方法将所有数据存入到位图中后,当查找时,只需要在位图中找到该位置,看比特位是否为1即可。需要注意的是,开空间时应该开N/32+1个大小的空间,因为c++中/号是整数除法向下取整。

概念

所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用
来判断某个数据存不存在的。

实现

 具体代码如下:

	template<size_t N>class bitset{public:bitset(){//_bits.resize(N/32+1, 0);_bits.resize((N>>5) + 1, 0);}void set(size_t x){size_t i = x / 32;size_t j = x % 32;_bits[i] |= (1 << j);}void reset(size_t x){size_t i = x / 32;size_t j = x % 32;_bits[i] &= ~(1 << j);}bool test(size_t x){size_t i = x / 32;size_t j = x % 32;return _bits[i] & (1<<j);}private:vector<int> _bits;};

这是简单的位图的实现,有时候还需要进行变形,如,找出海量数据中出现不超过两次的数字。

其实和这题道理一样,还是通过比特位来进行查找,我们可以开两个位图,那么在位图的相应位置会出现00 01 10 11四种情况,插入所有数据后再遍历一遍就可以找到这些数字。

布隆过滤器

解析

位图这个思想可以适用于整形,但是如果数据是字符串string就不太好实现,那么我们在哈希表中的用到的字符串哈希算法便可以很好的起到作用,我们把string通过算法转换为整形就能很好的映射到位图中,但是不同于整形的是,整形是一一对应的,而字符串转换后的值可能还是出现哈希冲突的情况,我们说过,哈希冲突是无法消除的,只能尽可能避免。

比如这种情况apple并不存在,但再查询时发现该位置为1,就会出现误判的情况。(insert的插入导致了该位置为1,但正好apple通过转换后也是映射到这个位置) 

这时布隆便想到了一种方法,我们可以把string通过算法转换为多个不同的整形,实现一对多的映射关系,这样就能大大提高准确率。实际中,通常用三个不同的算法进行转换。

在这种方法下,即使出现了交叉,还可以通过其他的位置来进行判断,这样就能提高准确率。

现在我们来想一个问题,我查询一个值,得到的结果有两种:

一个是存在,一个是不存在,那么在结果的角度看哪种结果是可靠的呢?

 还是拿这个图片来鞭尸,我们发现返回存在这种情况是不可靠的,因为它可能出现映射位置相同的情况,但该字符串并没有在位图中。返回不存在是可靠的,因为如果不存在,查找该位置的比特位为0,说明不可能有值在这里存在过。

实现

现在我们来进行实现,我们用三个比较优秀的算法来对字符串进行处理。如下:

struct BKDRHash
{size_t operator()(const string& key){// BKDRsize_t hash = 0;for (auto e : key){hash *= 31;hash += e;}return hash;}
};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;}
};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 BloomFilter
{
public:void Set(const K& key){size_t hash1 = HashFunc1()(key) % N;size_t hash2 = HashFunc2()(key) % N;size_t hash3 = HashFunc3()(key) % N;_bs.set(hash1);_bs.set(hash2);_bs.set(hash3);/*cout << hash1 << endl;cout << hash2 << endl;cout << hash3 << endl << endl;*/}// 一般不支持删除,删除一个值可能会影响其他值// 非要支持删除,也是可以的,用多个位标记一个值,存引用计数void Reset(const K& key);bool Test(const K& key){// 判断不存在是准确的size_t hash1 = HashFunc1()(key) % N;if (_bs.test(hash1) == false)return false;size_t hash2 = HashFunc2()(key) % N;if (_bs.test(hash2) == false)return false;size_t hash3 = HashFunc3()(key) % N;if (_bs.test(hash3) == false)return false;// 存在误判的return true;}private:bit::bitset<N> _bs;
};

判断时,如果有一个位为0,直接返回false,而且是准确的,都不为0返回true,但存在误判。

这就是位图和布隆过滤器的实现,创作不易,恳求点赞关注谢谢谢谢谢谢谢谢

相关文章:

  • RabbitMQ核心机制——延迟队列
  • win11 禁用/恢复 内置笔记本键盘(保证管用)
  • 【公式】MathType公式右编号对齐
  • MySQL连接错误解决方案:Can‘t connect to MySQL server on ‘localhost‘ (10038)
  • leetcode2081. k 镜像数字的和-hard
  • 华为OD机试真题——仿LISP运算(2025B卷:200分)Java/python/JavaScript/C/C++/GO最佳实现
  • 【短距离通信】【WiFi】WiFi7起源和应用场景介绍
  • MySQL 定时逻辑备份
  • CI/CD (持续集成/持续部署) GitHub Actions 自动构建
  • GitLab-CI将项目Wiki自动部署到文档中心
  • 卷积神经网络(CNN)深度讲解
  • 【HarmonyOS5】DevEco Studio 预览器与模拟工具详解
  • 基于文本挖掘与情感分析的B站《唐探1900》弹幕研究
  • 使用Cursor生成需求文档+UI设计图
  • 【微服务】SpringBoot 对接飞书审批流程使用详解
  • Python GDAL 库离线安装
  • NTFS0x90属性和0xa0属性和0xb0属性的一一对应关系是index_entry中的index_node中VCN和runlist和bitmap
  • Mybatis框架的构建(IDEA)
  • 【C++】21. 红黑树的实现
  • JWT与布隆过滤器结合使用指南
  • 网站建设 环保素材/网站网络推广推广
  • 揭阳网站开发/荆州网站seo
  • 定制一个网站多少钱/关键词热度分析工具
  • 商务网站建站/冯站长之家
  • 北京注册网站/市场推广
  • 惠州自适应网站建设/国内前10电商代运营公司