【C++高阶】哈希之美:探索位图与布隆过滤器的应用之旅

📝个人主页🌹:Eternity._
⏩收录专栏⏪:C++ “ 登神长阶 ”
🤡往期回顾🤡:模拟实现unordered 的奥秘
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

❀哈希应用

  • 📒1. 位图
    • 🌄位图的概念
    • 🏞️位图的实现
  • 📜2. 布隆过滤器
    • 🌈布隆过滤器概念
    • 🌞布隆过滤器的插入
    • 🌙布隆过滤器的查找
    • ⭐布隆过滤器的优点和缺陷
  • 📚3. 海量数据题目
    • 🧩哈希切分
  • 📖4. 总结


前言:在数据科学的浩瀚星空中,哈希函数犹如一颗璀璨的星辰,以其独特的光芒照亮了数据处理的每一个角落。哈希,这一简单而强大的技术,通过将任意长度的输入(如字符串、数字等)映射到固定长度的输出(即哈希值),实现了数据的快速定位与索引。然而,哈希的魅力远不止于此,当它与位图和布隆过滤器相结合时,更是催生出了一系列高效且实用的数据处理方案

位图(Bitmap)但是库里面:bitset,作为一种基于位操作的数据结构,以其极低的内存占用和高效的查询性能,在数据去重、频繁项集挖掘等领域展现出了非凡的潜力。通过将数据映射到位图的特定位上,我们可以实现快速的数据检索和统计,极大地提升了数据处理的速度和效率。

而布隆过滤器(Bloom Filter),则是在位图的基础上进一步创新的杰作。它通过引入多个哈希函数和位数组的组合,巧妙地实现了对大量数据的高效检索和去重,同时允许一定程度的误判率,从而在空间效率和查询速度之间取得了完美的平衡。布隆过滤器的这一特性,使得它在网络爬虫去重、垃圾邮件过滤、数据库索引优化等多个领域得到了广泛的应用。

本文将带您踏上一场探索哈希应用、位图与布隆过滤器的旅程。我们将从哈希函数的基本原理出发,逐步深入到位图和布隆过滤器的内部工作机制,通过生动的案例和详细的解释,让您了解这些技术是如何相互协作,共同解决现实世界中的复杂问题的

让我们一起踏上学习的旅程,探索它带来的无尽可能!


📒1. 位图

🌄位图的概念

我们直接介绍位图的话,大家可能没那么好理解,我们先通过一道面试题来带领大家,看看位图的应用场景

面试题:
在这里插入图片描述
解决办法:

  • 遍历,时间复杂度O(N)
  • 排序(O(NlogN)),利用二分查找: logN
  • 位图解决

大家在没学习位图之前,通常会用前两个方法来解决这个问题,但是前两个办法真的能够解决吗?对于这种海量数据,可能我们在使用前两种办法时,根本没有这么多的空间给你使用,因此我们就搞出了位图这个东西

位图解决:数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在
在这里插入图片描述

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


位图的应用:

  • 快速查找某个数据是否在一个集合中
  • 排序 + 去重
  • 求两个集合的交集、并集等
  • 操作系统中磁盘块标记

🏞️位图的实现

在这里插入图片描述


代码示例 (C++):

template<size_t N>
class bitset
{
public:// 构造函数bitset(){_bits.resize(N / 32 + 1, 0);}// ...... 其他待实现的函数
private:vector<int> _bits;
};

关于位图的模拟实现,我们只需要将它最常用的3个函数实现就够用了

  • set:将一个数据放入位图中
  • reset:将一个数据从位图中删掉
  • test:检测一个数据在不在位图中

set的模拟实现
在这里插入图片描述
最后的运算我们也只需要将1移位过去进行|运算


reset的模拟实现

reset的模拟实现和set只需要将最后一步反过来:1 -> 0,但是我们没有办法将0进行移位,所以我们依旧是将1移位过去进行,但是在运算前我们进行~取反,然后进行&运算


test的模拟实现

test的模拟实现我们只需要判断该数据的映射位置是否为1就行,还是比较简单的


代码实现 (C++):

template<size_t N>
class bitset
{
public:bitset(){// 构造函数,我们在需要的空间基础上 +1_bits.resize(N / 32 + 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;
};

📜2. 布隆过滤器

我们在使用新闻客户端看新闻时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉那些已经看过的内容。问题来了,新闻客户端推荐系统如何实现推送去重的? 用服务器记录了用户看过的所有历史记录,当推荐系统推荐新闻时会从每个用户的历史记录里进行筛选,过滤掉那些已经存在的记录。 如何快速查找呢?

  • 用哈希表存储用户记录,缺点:浪费空间
  • 用位图存储用户记录,缺点:位图一般只能处理整形,如果内容编号是字符串,就无法处理了
  • 将哈希与位图结合,即布隆过滤器

🌈布隆过滤器概念

布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间

在这里插入图片描述
在这里插入图片描述


代码示例 (C++):

template<size_t N, class K = string>
class BloomFilter
{
public:// ...... 其他待实现的函数
private:bitset<N> _bs;
}

注意:布隆过滤器的底层是上面讲到的位图

如果想要更深入的了解可以阅读一下这篇文章:
布隆过滤器详解


🌞布隆过滤器的插入

布隆过滤器的应用通常是string类型的参数,因此我们需要和之前哈希一样,将他们转化成整形,而布隆过滤器一般会映射到3个位置,因此我们会有3个不同仿函数来计算

在这里插入图片描述


仿函数示例 (C++):

struct BKDRHash
{size_t operator()(const string& key){size_t hash = 0;for (auto e : key){e *= 31;hash += e;}return hash;}
}; struct APHash
{size_t operator()(const string& key){size_t hash = 0;size_t ch;for (size_t i = 0; i < key.size(); i++){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;}
};

插入代码示例 (C++):

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);
}

🌙布隆过滤器的查找

分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个为零,代表该元素一定不在哈希表中,否则可能在哈希表中

注意:布隆过滤器如果说某个元素不存在时,该元素一定不存在,如果该元素存在时,该元素可能存在,因为有些哈希函数存在一定的误判


查找代码示例 (C++):

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;
}

在这里插入图片描述

布隆过滤器如果说某个元素不存在时,该元素一定不存在
如果该元素存在时,该元素可能存在


⭐布隆过滤器的优点和缺陷

优点:

  • 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无
  • 哈希函数相互之间没有关系,方便硬件并行运算
  • 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势
  • 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势
  • 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能
  • 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

缺陷:

  • 有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中(补救方法:再
    建立一个白名单,存储可能会误判的数据)
  • 不能获取元素本身
  • 一般情况下不能从布隆过滤器中删除元素
  • 如果采用计数方式删除,可能会存在计数回绕问题

📚3. 海量数据题目

🧩哈希切分

在这里插入图片描述
不管文件大小,我们都是直接读取到内存,然后插入set

  • 情况一:文件很多重复,后面重复插入都是失败,因此我们可以直接插入到set中
  • 情况二:不断插入set后,内存不足,会抛异常,因此我们要换哈希函数,进行二次切分

位图应用:

  • 给定100亿个整数,设计算法找到只出现一次的整数?
  • 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
  • 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整

布隆过滤器:

  • 给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出
    精确算法和近似算法
  • 如何扩展BloomFilter使得它支持删除元素的操作

📖4. 总结

随着我们对哈希应用、位图与布隆过滤器的深入探讨,不难发现,这些技术不仅仅是数据科学工具箱中的简单工具,它们更是智慧与创新的结晶,为数据的快速处理、高效检索和精确去重提供了强有力的支持

哈希函数以其独特的映射能力,为我们打开了一扇通往高效数据处理的大门。而位图,则以其极低的内存占用和快速的查询性能,成为了处理大规模数据集时的得力助手。至于布隆过滤器,它更是在继承位图优势的基础上,通过引入哈希函数的组合,实现了对大量数据的快速检索与去重,虽然伴随着一定的误判率,但其在空间效率与查询速度之间的精妙平衡,让它在众多应用场景中大放异彩

随着数据量的持续增长和数据处理需求的日益复杂,我们有理由相信,哈希应用、位图与布隆过滤器等高效数据处理技术将会得到更加广泛的应用和深入的研究。它们将继续在数据科学的舞台上发光发热,为我们揭示更多数据背后的秘密和价值

我们期待每一位读者都能从本次探索中汲取到宝贵的知识和经验,保持对新技术、新知识的好奇心和求知欲,不断探索、不断学习、不断进步
在这里插入图片描述
希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/49195.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++中的虚函数与多态机制如何工作?

在C中&#xff0c;虚函数和多态机制是实现面向对象编程的重要概念。 虚函数是在基类中声明的函数&#xff0c;可以在派生类中进行重写。当基类的指针或引用指向派生类的对象时&#xff0c;通过调用虚函数可以实现动态绑定&#xff0c;即在运行时确定要调用的函数。 多态是指通…

Cocos Creator 小游戏案例

最近在计划学习小游戏开发&#xff0c;查阅了一些资料&#xff0c;也找到了许多有趣的案例&#xff0c;特此记录与大家分享。 1. 连点成线 http://game.zaiwuchuan.com/yibihua 2. 颜色分类 http://game.zaiwuchuan.com/zhaoxiansuo 3. 星空一笔画 http://game.zaiwuchu…

大模型llama结构技术点分享;transformer模型常见知识点nlp面经

1、大模型llama3技术点 参考&#xff1a;https://www.zhihu.com/question/662354435/answer/3572364267 Llama1-3&#xff0c;数据tokens从1-2T到15T;使用了MHA&#xff08;GQA缓存&#xff09;&#xff1b;上下文长度从2-4-8K&#xff1b;应用了强化学习对其。 1、pretraini…

分布式事务(典型的分布式事务场景+CAP+解决方案)

分布式事务与分布式锁的区别&#xff1a; 分布式锁解决的是分布式资源抢占的问题&#xff1b;分布式事务和本地事务是解决流程化提交问题。 SQL中的4个事务隔离级别&#xff1a;&#xff08;1&#xff09;读未提交&#xff08;2&#xff09;读已提交&#xff08;3&#xff09…

如何远程开发完整分析一台新能源车BMS电池管理系统CAN数据矩阵

随着我国新能源汽车的崛起&#xff0c;从网络管理平台、数据中心、科研机构、高校教学、车型对标、整车DBC控制策略分析、电池管理系统研究、电池健康管理、网约车管理、电池梯度利用、车队管理等多方面的市场需求&#xff0c;完整分析一台新能源车BMS电池管理系统的CAN矩阵开发…

【深度学习】yolov8-seg分割训练,拼接图的分割复原

文章目录 项目背景造数据训练 项目背景 在日常开发中&#xff0c;经常会遇到一些图片是由多个图片拼接来的&#xff0c;如下图就是三个图片横向拼接来的。是否可以利用yolov8-seg模型来识别出这张图片的三张子图区域呢&#xff0c;这是文本要做的事情。 造数据 假设拼接方式有…

生成式AI与自然语言处理的结合-提升生成式AI的语言理解能力

引言 近年来&#xff0c;生成式AI已逐渐成为科技发展的前沿领域&#xff0c;其未来发展方向备受关注。对于人类生活和工作方式的影响&#xff0c;生成式AI在对话系统&#xff08;Chat&#xff09;和自主代理&#xff08;Agent&#xff09;中的表现引发了广泛讨论。本文将全面探…

Postman中的API Schema验证:确保响应精准无误

Postman中的API Schema验证&#xff1a;确保响应精准无误 在API开发和测试过程中&#xff0c;验证响应数据的准确性和一致性是至关重要的。Postman提供了一个强大的功能——API Schema验证&#xff0c;它允许开发者根据预定义的JSON Schema来检查API响应。本文将详细介绍如何在…

微软全球蓝屏带来的思考及未来战争走向

微软全球蓝屏事件不仅揭示了技术层面的问题和挑战&#xff0c;还引发了对未来战争走向的一些深入思考。以下是关于这些思考的内容&#xff1a; 微软全球蓝屏带来的思考&#xff1a; 系统稳定性与安全性&#xff1a;微软全球蓝屏事件凸显了操作系统稳定性和安全性的重要性。一…

Oracle配置TCPS加密协议测试

文章目录 一、环境信息二、配置过程1.创建证书2.监听配置2.1.配置sqlnet.ora2.2.配置listener.ora文件2.3.配置tnsnames.ora文件2.4.重载监听 3.数据库本地测试3.1. tcps登录测试3.2.日志监控 一、环境信息 操作系统&#xff1a;Linux 版本信息&#xff1a;Oracle 19c 参考文档…

asp.net core 集成redis详解

ASP.NET Core 集成 Redis 详解如下&#xff1a; 目录 一、Redis简介 二、在ASP.NET Core中集成Redis 三、Redis的高级用法 四、注意事项 一、Redis简介 Redis是一个开源的内存数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息代理。Redis内置了复制、Lua脚本、…

在可编辑 div (contentEditable)末尾插入换行符(\n 或 \<br\>)无效的解决办法

背景: 给可编辑 div 末尾插入换行符, 发现仍然未换行; 解决方法: 提前给 div 末尾插入一个 <br> 就行了, 之后看自己情况要不要去掉 示例代码: // 如果输入框末尾没有 BR 换行符, 则自动加一个, 避免 Ctrl Enter 两次才显示 const currLastEl dom_input.lastElement…

缓存框架 Caffeine 的可视化探索与实践

作者&#xff1a;vivo 互联网服务器团队- Wang Zhi Caffeine 作为一个高性能的缓存框架而被大量使用。本文基于Caffeine已有的基础进行定制化开发实现可视化功能。 一、背景 Caffeine缓存是一个高性能、可扩展、内存优化的 Java 缓存库&#xff0c;基于 Google 的 Guava Cac…

Ubuntu20.04 设置静态ip

Ubuntu 从 17.10 开始&#xff0c;已放弃在 /etc/network/interfaces 里固定 IP 的配置&#xff0c;interfaces 文件不复存在&#xff0c;即使配置也不会生效&#xff0c;而是改成 netplan 方式 &#xff0c;配置写在 /etc/netplan/01-netcfg.yaml &#xff0c;50-cloud-init.y…

机器学习笔记-02-基础线性算法认识(问题-解答自查版)

前言 以下问题以Q&A形式记录&#xff0c;基本上都是笔者在初学一轮后&#xff0c;掌握不牢或者频繁忘记的点 Q&A的形式有助于学习过程中时刻关注自己的输入与输出关系&#xff0c;也适合做查漏补缺和复盘。 本文可以让读者用作自查&#xff0c;答案在后面&#xff0…

跟《经济学人》学英文:2024年07月20日这期 At last, Wall Street has something to cheer

At last, Wall Street has something to cheer 华尔街终于有值得欢呼的事情了 at last&#xff1a;终于&#xff1b;最后&#xff1b; Consumer banks, on the other hand, are starting to suffer 原文&#xff1a; Capital markets are twitchy. When interest rates spi…

数据危机!4大硬盘数据恢复工具,教你如何正确挽回珍贵记忆!

在这个数字化的时代&#xff0c;硬盘里的数据对我们来说简直太重要了。但糟糕的是&#xff0c;数据丢失这种事时不时就会发生&#xff0c;可能是因为不小心删了&#xff0c;硬盘坏了&#xff0c;或者中了病毒。遇到这种情况&#xff0c;很多人可能就慌了&#xff0c;不知道怎么…

货架管理a

路由->vue的el标签->Api->call方法里calljs的api接口->数据声明const xxxData-> 编辑按钮:点击跳出页面并把这一行的数据给到表单formDataba2 保存按钮:formDataba2改过的数据->xxApi发送->查询Api 跳转仓库:把tableData.value数据清空->callXxxAp…

Windows环境下安装Redis并设置Redis开机自启

文章目录 0. 前言1. 下载 Windows 版本的Redis2. 为 Redis 设置连接密码&#xff08;可选&#xff09;3. 启动 Redis4. 设置 Redis 开机自启4.1 将 Redis 进程注册为服务4.2 设置 Redis 服务开机自启4.3 重启电脑测试是否配置成功4.4 关闭 Redis 开机自启&#xff08;拓展&…

Typora笔记上传到CSDN

1.Typora 安装 Typora链接&#xff1a;百度网盘 提取码&#xff1a;b6d1 旧版本是不需要破解的 后来的版本比如1.5.9把放在typora的根目录下就可以了 2.上传到CSDN 步骤 csdn 写文章-使用MD编辑器-导入本地md文件即可 问题 图片没法显示 原因 图片的链接是本地的 当然没法…