C++:由哈希延伸出来的应用--位图和布隆过滤器

news2024/11/24 6:07:49

文章目录

  • 位图的概念
  • 位图的实现
  • 布隆过滤器
    • 布隆过滤器的查找
    • 布隆过滤器的删除
    • 布隆过滤器的优点
  • 布隆过滤器的实现

本篇实现的是位图和应用

位图的概念

下面有这样的场景:给定40亿个数,现在要找这当中的一个数,如何寻找?

  1. 遍历,一个一个比对
  2. 排序+二分查找
  3. 位图

如何用位图解决?基本逻辑如下

在这里插入图片描述
在使用位图前,要先明确计算机中的大小是如何计算的

1 Byte = 8 Bits
1 KB = 1024 Bytes
1 MB = 1024 KB
1 GB = 1024 MB

也就是说,1GB大概是10亿个字节

那么在这个情景下,很明显,哪怕这40亿个数都不一样,也仅仅占用了40亿个比特位,也只是500MB左右的量级

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

位图的实现

#pragma once
#include <iostream>
#include <vector>
using namespace std;

// N是要存储的元素个数
template<size_t N>
class bitmap
{
public:
	// 构造函数
	bitmap()
		:_size(0)
	{
		size_t size = (N / 8) + 1;
		_map.resize(size, 0);
	}
	~bitmap()
	{
		_map.clear();
	}

	// 插入元素
	void set(size_t x)
	{
		// 找到这个元素属于的下标
		size_t i = x / 32;
		// 找到这个元素所属的比特位
		size_t j = x % 32;
		// 把这个元素标记一下
		_map[i] |= (1 << j);
		_size++;
	}

	// 删除元素
	void reset(size_t x)
	{
		// 找到元素下标和比特位
		size_t i = x / 32;
		size_t j = x % 32;
		// 把这个元素置0
		_map[i] &= ~(1 << j);
		_size--;
	}

	// 判断一个值在不在位图里面
	bool test(size_t x)
	{
		// 找到它在位图的位置
		size_t i = x / 32;
		size_t j = x % 32;
		return _map[i] & (1 << j);
	}

	// 查看
	void Print()
	{
		cout << "size:" << _size << endl;
		for (int i = 0; i < 100; i++)
		{
			if (test(i))
				cout << i << " ";
		}
		cout << endl;
	}
private:
	vector<int> _map;
	size_t _size;
};

位图的实现逻辑其实很简单,只是运用了一个位运算就可以解决了

位图的运用

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

布隆过滤器

什么是布隆过滤器?

简单来说,布隆过滤器是一种巧妙的概率型数据结构,它的优点主要体现在高效地插入和查询,用来表明这个东西一定不存在或者可能存在的问题,它的底层是用多个哈希函数,将一个数据映射到多个位图中,这样可以提高查找效率,也能节省空间

布隆过滤器的查找

布隆过滤器的底层如上面所示,因此被映射的位置的比特位是1,因此在寻找的时候就根据不同的哈希函数计算出对应的哈希值,再用每个对应的哈希值来看是否为0,如果这三个中有一个是0,那么就说明这个值不存在

布隆过滤器的误判情况

有下面的误判情况,比如说,现在有三个哈希函数,如果去这三个哈希函数对应的哈希值来到布隆过滤器中查找,会出现一些情况:如果有一个为0,那么绝对可以说明这个值是不存在的,但是反之却不能这么说,如果全都存在,也依旧会有不存在的可能,可能程序计算出的哈希值已经被映射过了,这样去对应得到的结果也依旧是存在的,但是很显然它本身是不存在的,所以布隆过滤器是存在误判的现象的

因此,使用合适的哈希函数可以尽可能的把误判的情况减少,减少它出现的概率,但是想要真正的出现一次都不进行误判还是有一定的难度,只能是尽可能的降低这种情况出现的概率与可能性

布隆过滤器的删除

布隆过滤器的删除其实是有些许问题的,这个问题其实很好想明白,如果此时的测试用例就是上面出现误判的这个测试用例,那么此时如果这个东西不存在,但是通过搜索发现它本身在这个过滤器中存在,并且还把它删除,那么就意味着这会出现其他映射值的问题,哪怕是这个值本身是存在的,直接贸然把位图中对应的值置为0也会出现很多问题

对于这样的情况,实际上还是有解决方案的,一个经典的解决方案就是使用引用计数的方法,在每个值的下面多一个计数器,当插入数据的时候就对它加1,删除数据的时候就对它减1,这样可以进行一定程度的优化,但是也并不能真正的解决误判对布隆过滤器带来的影响

布隆过滤器的缺陷

  1. 不能确定这个元素是不是真正的存在于布隆过滤器中
  2. 可能存在计数回绕的问题

布隆过滤器的优点

  1. 布隆过滤器的优点还是很明显的,它的优点主要就是体现在查找相当快,只需要根据哈希函数计算出哈希值然后进行比对就可以了
  2. 哈希函数相互没有关系,方便硬件进行运算
  3. 布隆过滤器不需要存储元素本身,它存储的是这个元素所对应的哈希值,因此对于隐秘数据可以做很好的保护
  4. 如果可以接受一定程度的误判的情况下,过滤器还是比其他的数据结构的比对要方便很多
  5. 数据量很大的时候,布隆过滤器可以表示全集
  6. 使用同一组散列函数的布隆过滤器可以进行交并差集运算

布隆过滤器的实现

#pragma once
#include <bitset>
#include <string>
using namespace std;

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

	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:
	bitset<N> _bs;
};

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

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

相关文章

box-sizing属性,IE怪异盒模型

有没有遇到过这种情况&#xff1f; 当一个放在整个页面的容器&#xff0c;它的宽度定义为 width:100%; 之后。假设再添加 padding &#xff0c;border 或者 margin 则会溢出父容器&#xff0c;是向外扩张的&#xff0c;也就是说设置了之后看不到效果。 首先看盒模型&#xf…

linux下的工具---yum

一、什么是yum yum是Linux下的软件包管理器 二、什么是软件包管理器 1、在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. 2、但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在…

【实战教程】PHP与七牛云的完美对接,你值得拥有!

前言&#xff1a; 随着互联网的迅速发展&#xff0c;越来越多的网站和应用程序需要处理大量的图片、视频和其他文件。为了有效地存储和管理这些文件&#xff0c;并提供快速的内容分发服务&#xff0c;开发者们常常依赖于云存储和CDN服务提供商。 七牛云是一家领先的云存储和C…

如何使用技术SEO来优化产品轮播

SEO&#xff08;搜索引擎优化&#xff09;对你来说并不陌生。现代电子商务系统通常包含旨在吸引谷歌等搜索引擎机器人注意的关键字。 但是&#xff0c;技术 SEO 在代码和服务器级别调查电子商务 SEO 策略。它改善了网站的技术因素&#xff0c;例如页面加载的速度以及抓取的直接…

可移动框 弹窗 可拖拽的组件

电脑端: <template><divv-if"show"ref"infoBox"mousedown.stop"mouseDownHandler"class"info-box":style"styleObject"><slot></slot></div> </template> <script> export defa…

Spring 中存储 Bean 的相关注解

Bean的存 IoC控制反转&#xff0c;就是将对象的控制权交给Spring的IOC容器&#xff0c;由IOC容器创建及管理对象。 也就是bean的存储 类注解:五大注解 Controller&#xff08;控制器存储&#xff09; Service&#xff08;服务存储&#xff09; Component&#xff08;组件存储…

Spring第二课响应的完全,如何理解前后端互联

目录 一、响应 Control,RestController 1.Controller的源码&#xff0c;代表什么意思 2.返回数据 Responsebody 3.返回HTML片段 4.返回JSON 5.那么假如我们使用集合会怎么样呢 设置状态码&#xff0c;虽然不影响展示&#xff0c;但是确实显示起来也就是401的情况。 2.我…

ECShop 4.x collection_listSQL注入

漏洞描述 ECShop是一款B2C独立网店系统&#xff0c;适合企业及个人快速构建个性化网上商店。系统是基于PHP语言及MYSQL数据库构架开发的跨平台开源程序 影响版本&#xff1a;ecshop4.0.7及以下 漏洞环境及利用 docker环境搭建 访问8080端口&#xff0c;数据库主机为mysql&a…

Spark---Master启动及Submit任务提交

一、Spark Master启动 1、Spark资源任务调度对象关系图 2、集群启动过程 Spark集群启动之后&#xff0c;首先调用$SPARK_HOME/sbin/start-all.sh&#xff0c;start-all.sh脚本中调用了“start-master.sh”脚本和“start-slaves.sh”脚本&#xff0c;在start-master.sh脚本中可…

LLM之Agent(二):BabyAGI的详细教程

BabyAGI是一个 AI 支持的任务管理系统&#xff08;Python脚本&#xff09;&#xff0c;使用 OpenAI 和 Pinecone API 创建, 优先级排序和执行任务。该系统背后的主要思想是基于先前任务的结果和预定义的目标创建任务。脚本然后使用 OpenAI 的自然语言处理&#xff08;NLP&#…

文献速递:超声影像人工智能专题文献分享

文献速递&#xff1a;超声影像人工智能专题文献分享 01 文献速递介绍 本文综述了超声影像组学在甲状腺疾病研究中的应用及其局限性。近年来&#xff0c;甲状腺疾病的发病率逐渐增加&#xff0c;传统超声是最关键的甲状腺成像方法之一&#xff0c;但仍存在一定局限性。超声影…

Syncovery Mac/win中文版:快速、方便的数据备份和同步工具

备份和同步数据是现代生活中不可或缺的任务。无论是个人用户还是企业用户&#xff0c;都需要一款可靠的工具来保护和同步他们的数据。Syncovery是一款备份数据和同步工具&#xff0c;它能够提供全面的数据保护和灵活的数据同步功能。 首先&#xff0c;Syncovery具有强大的备份…

每日一练:简易计算器

1.设计思路 创建一个简单的用户界面&#xff0c;可以使用 Python 的 Tkinter模块。在界面上放置按钮&#xff0c;每个按钮代表一个数字、运算符或其他功能。使用变量来追踪用户输入的表达式。在用户点击按钮时&#xff0c;更新表达式并在界面上显示。 当用户点击“”按钮时&am…

window关于下载anaconda 2023年以后的版本,jupyter notebook闪退,没有内核的问题

这种问题的解决办法&#xff1a; 下载anaconda较早版本&#xff0c;比如我下载的是&#xff1a;2022年5月的版本。 下载之后&#xff0c;打开jupyter好像也会没有内核和闪退。 下面解决步骤&#xff1a; 1.注意&#xff1a;打开anaconda powershell prompt 2.重点来了&#xf…

漏洞复现--致远 M3 反序列化 mobile_portal RCE

免责声明&#xff1a; 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…

Uni-app智慧工地可视化信息云平台源码

智慧工地的核心是数字化&#xff0c;它通过传感器、监控设备、智能终端等技术手段&#xff0c;实现对工地各个环节的实时数据采集和传输&#xff0c;如环境温度、湿度、噪音等数据信息&#xff0c;将数据汇集到云端进行处理和分析&#xff0c;生成各种报表、图表和预警信息&…

支持向量机:Python实践

支持向量机&#xff08;Support Vector Machine&#xff0c;简称SVM&#xff09;是机器学习领域中一种常用的分类算法&#xff0c;其在处理线性可分和线性不可分问题上表现出色。Python作为一种广泛应用的编程语言&#xff0c;提供了众多强大的机器学习库和工具&#xff0c;使得…

Mysql数据库多表数据查询问题

1、背景 线上某个业务数据分表存储在10个子表中&#xff0c;现在需要快速按照条件&#xff08;比如时间范围&#xff09;筛选出所有的数据&#xff0c;主要是想做一个可视化的数据查询工具&#xff0c;给产研团队使用。 2、实践 注意&#xff1a;不要在线上真实数据库操作&am…

【JavaEE初阶】 博客系统项目--前端页面设计实现

文章目录 &#x1f332;主要内容&#x1f38d;预期效果&#x1f6a9;博客列表页效果&#x1f6a9;博客详情页&#x1f6a9;博客登录页&#x1f6a9;博客编辑页 &#x1f340;实现博客列表页&#x1f6a9;实现导航栏&#x1f388;页面主体部分 &#x1f384;实现博客详情页&…

无公网IP环境如何实现远程访问连接家里内网的威联通QNAP NAS

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…