【C++进阶】哈希的应用之位图和布隆过滤器

位图和布隆过滤器

  • 一,位图
    • 1. 实现
    • 2. 位图的应用
  • 二,布隆过滤器
    • 1. 使用场景
    • 2. 模拟实现
  • 三,海量数据面试题
    • 哈希切分
  • 四,总结

这一节我们来看哈希的应用

一,位图

先来看一个面试题
在这里插入图片描述
这里如果用unordered_set来解决,是不可取的,因为一个整型4个Byte,40亿个整型那就是16个G,把这16个G直接放进内存是不合理的,所以就要用到位图。
在这里插入图片描述

位图和哈希表相比,就是将每个数据元素映射到每一个比特位上。适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。

1. 实现

位图的实现比较简单,下面是位图bitset的一些常用接口:
在这里插入图片描述
首先我们要构造位图,确定好要开的空间大小
这里的构造需要传入所需要的比特位数,然后我们在实现时根据传入的N来确定相应的比特位
在这里插入图片描述
这里我们可以先写出bitset的框架:

template<size_t N>//非类型模板参数---表示需要多少个比特位去映射
class bitset {
public:bitset() {//构造函数根据需要的比特位来开相应的数组_bits.resize((N >> 5) + 1, 0);//除以2的5次方相当于右移5位}//...
private:vector<int> _bits;
};

这里我们也是只模拟实现主要的接口:
在这里插入图片描述
set的作用是将一个整型放入位图中,映射的时候我们先找到要映射的是第几个字节,然后再计算这个字节的第几个比特位,将这个比特位置为1即可

在这里插入图片描述

reset的作用是将数据从位图中删除,也就是将映射的比特位置为0

void set(size_t x) {//将映射到的位置置为1size_t i = x / 32;//i表示映射在数组的第几个整型中size_t j = x % 32;//j表示映射在第i个整型的第j位上_bits[i] |= (1 << j);//将映射到的位置置为1---用相应的数去 或等 (任何数和1或都为1,和0或为任何数)
}void reset(size_t x) {//将映射的位置置为0size_t i = x / 32;size_t j = x % 32;_bits[i] &= ~(1 << j);//将映射的位置置为0---将相应的数取反去 与等 (任何数和1与为如何数,和0与都为0)
}

位图解决的是在不在的问题,当然位图这种结构也有一个扩展的问题,就是找到第一次出现的数的这类问题,对于这类问题,其实就是用两个位图来存放一个数
在这里插入图片描述
具体的代码可以进入我的gitee仓库查看: 位图的实现

2. 位图的应用

对于位图来说,其只能存储整型的数据,所以其常见的应用就是如下几个:
在这里插入图片描述

二,布隆过滤器

1. 使用场景

对于位图而言,其只能处理整型的数据,如果要处理字符串类型呢,就无法处理了

我们如果简单地将字符串转换为整型,再映射到对应的位,那么就会出现多个字符串映射到同一个位的问题,因为整型最大只有32位,但是字符串可以有很多位
在这里插入图片描述
为了解决这样的问题我们可以让一个字符串映射到多个比特位上
在这里插入图片描述
这样的结构也会导致判断一个字符串不在是准确的,因为只要有一个比特位为0就是不在,判断在是不准确的,因为哈希函数存在误判。

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

至于为什么叫布隆过滤器,我们可以看下面的使用场景进行理解:
假设有一个注册页面需要你来创建用户名,如果这个用户名已经被创建,则需要换一个名称,那么面对大量的数据情况下,如果查找这个创建的用户名是否已经被申请了呢?总不可能每次都在后台的服务器上一个个查找吧,这时就可以借助布隆过滤器了,如果查找这个名称存在,则不可以创建,如果不在,则可以创建。这种场景下是允许误判的,因为判断一个不在的比误判一个存在的要合理
在这里插入图片描述

2. 模拟实现

下面我们来模拟实现一下,布隆过滤器底层用的其实也是位图,所以实现时我们直接用位图的接口即可
这里默认处理的类型是string,所以要有对应的哈希函数来将字符串转换为整型,这里我们直接用三种哈希函数来转换。

//这三个哈希函数造成的哈希冲突是最少的
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>//这里默认处理的是sting字符串,三个仿函数是哈希函数,将string映射成整型
class BloomFilter {
public:void set(const K& key){//将字符串经过哈希得到三个整型size_t hash1 = Hashfunc1()(key) % N;//仿函数匿名对象,%N是为了不超出Nsize_t hash2 = Hashfunc2()(key) % N;size_t hash3 = Hashfunc3()(key) % N;//再将这三个整型分别映射到三个比特位_b.set(hash1);_b.set(hash2);_b.set(hash3);}
private:bitset<N> _b;
};

完整代码可以参考这里:布隆过滤器

三,海量数据面试题

哈希切分

有这样一个问题
在这里插入图片描述
这里有两个100亿的查询字符串query,是不可能将这两个字符串放进内存直接查询的,所以就要做到哈希切割
在这里插入图片描述
这样切分后,每个小文件都是相同的数据元素,找交集时会在相同的文件中查找

但是如果切分后的小文件还是很大怎么办

切分后的小文件很大的原因有两个
1.一个文件中都是相同的query
2.这个文件中很多不同的query
如果遇到这种问题,则继续将这个小文件放入set中,如果是第一种情况,那么在放入set中时,重复的元素不会被存入
如果是第二种情况,则继续进行哈希切分处理。

四,总结

哈希这部分我们也算是讲解完了,哈希的用途还是非常的广。希望大家可以对哈希有一个深入的理解。C++学到这里其实也走过了大部分了,但是在这里我想说基础还是很重要的,基础越牢固,后面的学习才会更快。希望大家都可以打好基础,对C++有深入的学习。

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

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

相关文章

多叉树题目:子树中标签相同的结点数

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;子树中标签相同的结点数 出处&#xff1a;1519. 子树中标签相同的结点数 难度 5 级 题目描述 要求 给你一个树&#xff08;即一个连通的无向无环图…

MySQL高级篇(B-Tree、Btree)

目录 1、Btree&#xff08;B-Tree&#xff09; 1.1、B-Trees的特点 二叉树缺点&#xff1a;顺序插入时&#xff0c;会形成一个链表&#xff0c;查询性能大大降低。大数据量情况下&#xff0c;层级较深&#xff0c;检索速度慢。红黑树&#xff1a;大数据量情况下&#xff0c;层…

10款白嫖党必备的ai写作神器,你都知道吗? #媒体#人工智能#其他

从事自媒体运营光靠自己手动操作效率是非常低的&#xff0c;想要提高运营效率就必须要学会合理的使用一些辅助工具。下面小编就跟大家分享一些自媒体常用的辅助工具&#xff0c;觉得有用的朋友可以收藏分享。 1.飞鸟写作 这是一个微信公众号 面向专业写作领域的ai写作工具&am…

rsync+inotify实时同步 和 GFS分布式文件系统概述

目录 一、rsyncinotify实时同步 1.1.实时同步的优点 1.2.Linux内核的inotify机制 1.3.发起端配置rsyncInotify 1.4.配置远程登陆 1.4.1.修改rsync源服务器配置192.168.190.101 ​编辑 1.4.2.配置server 192.168.190.102 二、GFS 2.1.GlusterFS简介 2.2.GlusterFS特点…

python代码使用过程中使用快捷键注释时报错

1.代码 2.代码报错 3.代码注释后的结果 4. 原因

我去,PMP原来不是所有人都能报!

很多人可能觉得PMP的报名条件很复杂&#xff0c;又是经验要求&#xff0c;又是学历要求的&#xff0c;网络上关于PMP报名条件说的层出不穷&#xff0c;今天给大家统一一下&#xff0c;报名PMP究竟需要什么条件&#xff1a; 官方报考条件&#xff1a; 一、报名考生必须具备35小…

动态输出n位小数——满满都是坑!

【题目描述】 输入正整数a&#xff0c;b&#xff0c;c&#xff0c;输出a/b的小数形式&#xff0c;精确到小数点后c位。a,b ≤10^6 &#xff0c;c≤100。输入包含多组数据&#xff0c;结束标记为a&#xff1d;b&#xff1d;c&#xff1d;0。 【样例输入】 1 6 4 0 0 0 【样…

Windows:IntelliJ IDEA Ultimate 安装 PHP 插件

在 IntelliJ IDEA Ultimate 中安装 PHP 插件&#xff0c;支持PHP开发调试 首先&#xff0c;进入File > Setting&#xff1a; 再次选择Plugins&#xff0c;然后选择上面的 Marketplace。 在搜索栏中输入 PHP&#xff0c;然后单击左侧的 Install 进行安装就可以了。 安装成功…

关于Ansible模块 ⑤

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 继《关于Ansible的模块 ①》、《关于Ansible的模块 ②》与《关于Ansible的模块 ③》之后&#xff0c;继续学习ansible常用模块之…

Cannot find runner for app ——Android Studio

问题 在修改build.gradle(:app)文件或者其他操作后&#xff0c;出现了无法运行的问题&#xff1a; Cannot find runner for app 如图运行按钮不可点击。 解决方案 点击【File】下的【Sync Project with Gradle Files】同步完成后&#xff0c;一般就可运行了。

ENSP USG防火墙接入虚拟机;开启Web访问;

1.添加防火墙及云&#xff0c;启动防火墙&#xff1b; 2.配置桥接网卡&#xff1b; 默认账户&#xff1a;admin 默认密码&#xff1a;Admin123 #第一次登陆需修改密码&#xff1b; 默认G0/0/0口为管理口&#xff0c;而在模拟器中进入防火墙的web需如下配置&#xff1a; 配置 …

聊一下Redis实现分布式锁的8大坑

前两篇文章都在讲 Redis 的 5 大常用数据类型&#xff0c;以及典型的 10 大应用场景。 那么今天就来看看 Redis 实现分布式锁。 聊一聊Redis实现分布式锁的8大坑 Redis中5大常见数据类型用法 工作中Redis用的最多的10种场景 在分布式系统中&#xff0c;保证资源的互斥访问是…