【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) {//将映射到的位置置为1
	size_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) {//将映射的位置置为0
	size_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)
	{
		// BKDR
		size_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是为了不超出N
		size_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++有深入的学习。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JS--demo2录入学生信息

实现学生信息录取。 效果图: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><meta http-equiv"X-U…

SSL证书的作用是什么?

SSL证书让网站和用户之间安全传输信息&#xff0c;就像给网络对话加了一把密码锁。它主要做四件事&#xff1a; 1. 证明身份&#xff1a; - 像警察局一样&#xff0c;有个叫“证书颁发机构”的家伙负责检查网站是不是真的。网站要向它证明自己是谁&#xff08;比如&#xff0c;…

onedrive 清理文件历史版本 节省空间

onedrive 清理文件历史版本以节省空间的操作步骤 起因&#xff1a; 用的好好的onedrive高校教育版&#xff0c;突然在2024年4月2日晚上把空间从1T回收到100G&#xff0c;然后文件爆满&#xff0c;虽然没有把文件都给我删了&#xff0c;但是可能几个月窗口期过去就没文件了。而…

如何恢复被.locked勒索病毒加密的服务器和数据库?

.locked勒索病毒有什么特点&#xff1f; .locked勒索病毒的特点主要包括以下几个方面&#xff1a; 文件加密&#xff1a;.locked勒索病毒会对受感染设备上的所有文件进行加密&#xff0c;包括图片、文档、视频和其他各种类型的重要文件。一旦文件被加密&#xff0c;文件的扩展…

电商运营自动化新里程:取数宝引领数字化转型实践

随着电子商务行业的高速发展及复杂化&#xff0c;精细化运营已成为电商企业提升竞争力的关键所在。尤其是在海量数据处理与实时分析方面&#xff0c;自动化工具的引入对企业管理和决策带来了革命性变化。其中&#xff0c;“取数宝”作为一种先进的电商运营自动化解决方案&#…

20240325-2-K-means面试题

K-means面试题 1. 聚类算法&#xff08;clustering Algorithms&#xff09;介绍 聚类是一种无监督学习—对大量未知标注的数据集&#xff0c;按数据的内在相似性将数据集划分为多个类别&#xff0c;使类别内的数据相似度较大而类别间的数据相似度较小。 聚类算法可以分为原型…

从零自制docker-8-【构建实现run命令的容器】

文章目录 log "github.com/sirupsen/logrus"args...go moduleimport第三方包失败package和 go import的导入go build . 和go runcli库log.SetFormatter(&log.JSONFormatter{})error和nil的关系cmd.Wait()和cmd.Start()arg……context.Args().Get(0)syscall.Exec和…

X86汇编速成

平时用的电脑都是X86的&#xff0c;但是现在大家都在搞RISC-V&#xff0c;计组也都开始以RISC-V作为示例&#xff0c;所以专门回头来补一下X86的汇编&#xff0c;方便平时使用。 寄存器register X86_64中一共有16个64位的通用寄存器&#xff0c;分别为&#xff1a; RAX, RBX,…

分享一款嵌入式开源按键框架代码工程MultiButton

目录 1 工程简介 2 工程代码分析 3 工程代码应用 4 思考 1 工程简介 MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块。 Github地址&#xff1a;https://github.com/0x1abin/MultiButton 这个项目非常精简&#xff0c;只有两个文件&#xff1a; &#xff08;1&am…

前端layui自定义图标的简单使用

iconfont-阿里巴巴矢量图标库 2. 3. 4.追加新图标 5.文件复制追加新图标

OSPF实验

需求&#xff1a; 1、R1-R3为区域0&#xff0c;R3到R4为区域1&#xff1b;其中R3的环回也在区域0&#xff0c;P1-R3分别有一个环回接口 2、R1-R3 R3为DR设备&#xff0c;没有BDR 3、R4环回地址已固定&#xff0c;其他所有网段使用192.168.1.0/24进行合理分配 4、R4环回不能…

鸿蒙ArkUI声明式学习:【UI资源管理】

OpenHarmony 应用的资源分类和资源的访问以及应用开发使用的像素单位以及各单位之间相互转换的方法。 资源分类 移动端应用开发常用到的资源比如图片&#xff0c;音视频&#xff0c;字符串等都有固定的存放目录&#xff0c;OpenHarmony 把这些应用的资源文件统一放在 resourc…

Golang中的上下文-context包的简介及使用

文章目录 简介context.Background()上下文取消函数上下文值传递建议Reference 简介 Go语言中的context包定义了一个名为Context的类型&#xff0c;它定义并传递截止日期、取消信号和其他请求范围的值&#xff0c;形成一个链式模型。如果我们查看官方文档&#xff0c;它是这样说…

6.10物联网RK3399项目开发实录-驱动开发之SPI接口的使用(wulianjishu666)

嵌入式实战开发例程&#xff0c;珍贵资料&#xff0c;开发必备&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1149x7q_Yg6Zb3HN6gBBAVA?pwdhs8b SPI 使用 SPI 简介 SPI 是一种高速的&#xff0c;全双工&#xff0c;同步串行通信接口&#xff0c;用于连接微控制器、…

拥有自己的云环境-域名及备案

序 唠叨两句 之前的文章&#xff0c;讲了如何购买一台云服务器&#xff0c;然后购买之后&#xff0c;如何操作云服务器。当买完云服务器之后&#xff0c;我们就可以使用云服务器提供的公网ip&#xff0c;访问到我们的服务器上。但是&#xff0c;这样怎么能体现我们一个老程序…

第十四届蓝桥杯岛屿个数

题目描述&#xff1a; 小蓝得到了一副大小为 MN 的格子地图&#xff0c;可以将其视作一个只包含字符 0&#xff08;代表海水&#xff09;和 1&#xff08;代表陆地&#xff09;的二维数组&#xff0c;地图之外可以视作全部是海水&#xff0c;每个岛屿由在上/下/左/右四个方向上…

使用 AI 生成正则表达式,告别正则烦恼

如果你有处理正则表达式的需求&#xff0c;那么这个网站&#xff08;autoregex.xyz&#xff09;一定要收藏好。 可以根据文字描述生成正则表达式。 默认是从文字到正则&#xff0c;不用选择。 输入框中输入描述&#xff0c;点击 ”GO“ 按钮。 等待一会儿&#xff0c;即可生…

测试开发面经(Flask,轻量级Web框架)

1. Flask的核心特点 a. 轻量级&#xff1a;核心简洁&#xff0c;只提供了基本的功能&#xff0c;其他高级功能可以通过插件或扩展来添加。 b. 灵活性&#xff1a;允许开发者选择适合自己项目的组件和工具&#xff0c;没有强制的项目结构和设计模式。 c. 易于扩展&#xff1a;提…

搭建python编译环境

目录 1.安装依赖包 2.安装失败进行换源 3. 更新系统 通过C 语言调用 Python 代码&#xff0c;需要先安装 libpython3 的 dev 依赖库&#xff08;不同的 ubuntu 版本下&#xff0c; python 版本 可能会有差异&#xff0c; 比如ubuntu 22.04 里是 libpython3.10-dev &#xff09…

javaScript手写专题——实现instanceof/call/apply/bind/new的过程/继承方式

目录 原型链相关 手写instanceof 实现一个_instance方法&#xff0c;判断对象obj是否是target的实例 测试 手写new的过程 实现一个myNew方法&#xff0c;接收一个构造函数以及构造函数的参数&#xff0c;返回构造函数创建的实例对象 测试myNew方法 手写类的继承 ES6&…