位图和布隆过滤器+哈希切分思想

news2024/9/29 1:23:00

在这里插入图片描述

文章目录

  • 一.位图(bitset)
    • 底层实现:
  • 二.布隆过滤器(bloomFilter)
    • 底层实现:
  • 三.哈希切分思想

一.位图(bitset)

  • 位图是一种以一个比特位为数据记录单元的哈希表 ,以无符号整数为key值,采用直接定址法(不存在哈希冲突的问题),其哈希映射函数为
    • f ( k e y ) = k e y ( k e y 的存在状态由第 k e y 个比特位来记录 ) f(key)=key(key的存在状态由第key个比特位来记录) f(key)=key(key的存在状态由第key个比特位来记录)
    • 比特位为1表示该映射位对应的key存在,比特位为0表示该映射位对应的key不存在
  • STL中的位图以vector<char>为适配容器,采用位运算的方式实现其功能接口
    在这里插入图片描述
    key存在状态的记录:
    在这里插入图片描述

底层实现:

//Size记录要存放的数据个数上限(非类型模板参数),即至少需要开辟Size个比特位的空间
template<size_t Size>
class bitset
{
public:
	bitset()
	{
		_table.resize((Size / 8) + 1, 0);
	}

	//将第key个比特位设置为1,表示key存在于集合中
	void set(size_t key)
	{
		//计算第key个比特位位于vector的第几个字节
		size_t bytes = key / 8;
		//计算第key个比特位位于某字节的第几个个比特位
		size_t bits = key % 8;
		//通过位运算将第key个比特位设置为1
		_table[bytes] |= (1 << bits);
	}

	//将第key个比特位设置为0,表示将数据key从集合中删除
	void reset(size_t key)
	{
		//计算第key个比特位位于vector的第几个字节
		size_t bytes = key / 8;
		//计算第key个比特位位于某字节的第几个个比特位
		size_t bits = key % 8;
		//通过位运算将第key个比特位设置为0
		_table[bytes] &= ~(1 << bits);
	}

	//查询key是否存在于集合中
	bool test(size_t key)
	{
		//计算第key个比特位位于vector的第几个字节
		size_t bytes = key / 8;
		//计算第key个比特位位于某字节的第几个个比特位
		size_t bits = key % 8;
		//通过位运算判断第key个比特位是否为1
		return _table[bytes] & (1 << bits);
	}


private:
	std :: vector<char> _table;
};
  • 位图只能记录关键字是否存在于集合中,但相比于红黑树和哈希桶,位图具有很高的空间效率和时间效率,非常适合用于处理海量数据:
    • bitset<-1> (-1转换成无符号整数) ,这样一个对象只占用512MB左右的内存,而它可以用于记录所有可能存在key值
    • 实际应用:
      1. 快速查找某个数据是否在一个集合中
      2. 数据排序 + 去重
      3. 求两个集合的交集、并集等
      4. 操作系统中磁盘块标记
  • 配合字符串哈希函数,位图可以用于记录字符串在研究集合中的存在状态,但是不同的字符串可能会对应同一个key值,为了降低不同字符串哈希冲突的概率,一个字符串可以用多个不同的字符串哈希函数多次映射到位图上,由这样的方式设计出的位图称为布隆过滤器

二.布隆过滤器(bloomFilter)

  • 同一个字符串通过多个不同的字符串哈希函数多次映射到同一张位图上,从而有效地降低了位图中字符串发生哈希冲突的概率在这里插入图片描述

底层实现:

  • 通过复用bitset实现:
//字符串哈希映射函数1
struct BKDRHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 0;
		for (auto ch : s)
		{
			hash += ch;
			hash *= 31;
		}

		return hash;
	}
};

//字符串哈希映射函数2
struct APHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 0;
		for (long i = 0; i < s.size(); i++)
		{
			size_t ch = s[i];
			if ((i & 1) == 0)
			{
				hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
			}
		}
		return hash;
	}
};

//字符串哈希映射函数3
struct DJBHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 5381;
		for (auto ch : s)
		{
			hash += (hash << 5) + ch;
		}
		return hash;
	}
};



// Size是最多不同key的个数
template<size_t Size,class Key = string,class Hash1 = BKDRHash,class Hash2 = APHash,class Hash3 = DJBHash>
class BloomFilter
{
public:
	void set(const Key& key)
	{
		size_t len = Size * _factor;

		//同一个字符串映射三次
		size_t hash1 = Hash1()(key) % len;
		_bs.set(hash1);

		size_t hash2 = Hash2()(key) % len;
		_bs.set(hash2);

		size_t hash3 = Hash3()(key) % len;
		_bs.set(hash3);

	}

	bool test(const Key& key)
	{
		size_t len = Size * _factor;


		//只有三个哈希映射都相同才认为关键字是重复的
		size_t hash1 = Hash1()(key) % len;
		if (!_bs.test(hash1))
		{
			return false;
		}

		size_t hash2 = Hash2()(key) % len;
		if (!_bs.test(hash2))
		{
			return false;
		}

		size_t hash3 = Hash3()(key) % len;
		if (!_bs.test(hash3))
		{
			return false;
		}


		return true;
	}
private:
	static const size_t _factor = 6;
	//由于一个key要占用三个比特位,因此需要额外开辟_factor倍数的空间
	bitset<Size * _factor> _bs;
};
  • 布隆过滤器的应用:
    1. 布隆过滤器不存储元素本身,在某些对数据保密要求比较严格的场合有很大优势
    2. 在能够承受一定的误判的场景下,布隆过滤器比其他数据结构时间和空间效率更高
    3. 数据量很大时,布隆过滤器可以表示数据全集,其他数据结构不能(受内存限制)
    4. 使用同一组哈希函数的布隆过滤器可以进行交、并、差运算
    • 游戏中昵称存在判断等重复数据过滤的场景经常使用布隆过滤器

三.哈希切分思想

  • 哈希切分思想是一种处理海量数据的思想方法—假如现在有100亿个字符串,计算机仅有1G的内存可供使用,如何设计算法找到出现次数最多的那个字符串呢?
    • 首先,对数据集合进行哈希切分,将其切分为N个子文件(N个子文件从0~N-1编号),切分方法是:用字符串哈希函数Hasn()得到每个字符串的key值,然后按照如下映射关系将每个字符串分类放到对应编号为i的子文件中:

    • i = H a s h ( k e y ) m o d    N i =Hash(key)\mod N i=Hash(key)modN在这里插入图片描述

    • 由于相同的字符串一定会被分类到相同的子文件中,因此将每个子文件分别加载到内存中用map进行统计即可.(如果某些子文件太大,则可以继续以相同的方式(用不同的字符串哈希函数)进行哈希切分)

  • 上述哈希切分方法还可以应用于如下的问题:现有文件A和文件B, 它们分别存储着100亿个字符串,计算机只有1G内存可供使用,如何得到两个文件的交集?
    • 一个高效的解决方式:将文件A和文件B分别进行哈希切分:在这里插入图片描述

    • 由于相同的字符串一定会被分类到编号相同的子文件中,因此将子文件Ai和Bi两两加载到内存中用set找出共同元素即可
      在这里插入图片描述

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

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

相关文章

有关合泰BA45F5260中断的思考

最近看前辈写的代码&#xff0c;发现这样一段代码&#xff1a; #ifdef SUPPORT_RF_NET_FUNCTION if(UART_INT_is_L()) { TmrInsertTimer(eTmrHdlUartRxDelay,TMR_PERIOD(2000),NULL); break; } #endif 其中UART_INT_is_L&am…

【lesson6】Linux下:第一个小程序,进度条代码

文章目录 准备工作sleep问题fflush回车与换行的区别 进度条代码 准备工作 sleep问题 首先我们来看一段代码&#xff1a; 这时候有个 问题这个代码是输出“hello world”还是先sleep三秒&#xff1f; 再来一段代码 这个代码是先sleep三秒还是先输出“hello world”&#xff…

「乐天世界」NFT 作品集

进入「乐天世界」NFT 作品集的迷人世界&#xff0c;这里仿佛就是乐天世界探险主题公园里充满活力的礼品店。 准备好随着想象力的飞跃而沉浸其中吧&#xff0c;因为主题公园里的普通物品已经变得非凡。沉浸在游乐园美食的魔力中&#xff0c;如香脆的玉米热狗、令人垂涎的巧克力蛋…

立创EDA学习

学习树莓派3B的板子发现有个扩展板比较好&#xff0c;自己最好画一个&#xff0c;反正免费。 学习视频&#xff1a;立创EDA&#xff08;专业版&#xff09;电路设计与制作快速入门。 下载专业版&#xff0c;并激活。【分专业版和标准版&#xff0c;专业版也是免费的】 手机…

基于物联网技术的能耗在线监测平台的架构设计与应用

安科瑞 华楠 摘要&#xff1a;围绕工业生产等领域节能降耗实际需求&#xff0c;提出基于物联网的能耗在线监测平台总体方案&#xff0c;面向政府、行业、企业提供能耗管理信息化管理与服务;研究设计能耗监测终端&#xff0c;支持多种工业总线及工业协议&#xff0c;实现电表、…

jenkins执行jmeter时,报Begin size 1 is not equal to fixed size 5

jenkins执行jmeter脚本的时候一直提示如下错误&#xff1a; Tidying up ... Fri Jul 28 17:03:53 CST 2023 (1690535033178) Error generating the report: org.apache.jmeter.report.dashboard.GenerationException: Error while processing samples: Consumer failed wi…

this关键字和同步异步宏认为微任务理解

目录 js面试常见问题&#xff1a;1.this指向 2.闭包定义和作用 3.原型链 4.异步协程 this关键字 this主要有以下几个使用场合。 1&#xff09;全局环境 &#xff08;2&#xff09;构造函数 &#xff08;3&#xff09;对象的方法 避免多层this 避免数组处理方法中的 this 避免回…

RabbitMQ 教程 | RabbitMQ 入门

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

VS CODE 20230728

VSCode添加至右键菜单 2.Visual Studio Code(VS Code)中文显示乱码的解决方法 1.按 快捷键 ctrl, 在搜索栏中输入“files:auto Guess Encoding” 勾选 还是乱码

UG\NX二次开发 获取2D制图视图中可见的对象,并获取类型

文章作者:里海 来源网站:https://blog.csdn.net/WangPaiFeiXingYuan 简介: 使用UF_VIEW_ask_visible_objects获取2D制图视图中可见的对象,并获取类型。 下面是将一个六面体以不同的视图投影,获取视图对象和类型的效果。 效果: 1个部件事例,1个体,4条边 1个部件事…

C++,类和对象-多态,制作饮品

#include<iostream> using namespace std;//多态案例&#xff0c;制作饮品class AbstractDrinking { public://煮水virtual void Boil() 0;//冲泡virtual void Brew() 0;//倒入茶杯virtual void PourInCup() 0;//加入辅料virtual void PutSomething() 0;//制作饮品vo…

外文期刊影响因子去哪里查询,如何查询

期刊影响因子(Impact factor&#xff0c;IF)&#xff0c;是代表期刊影响大小的一项定量指标。也就是某刊平均每篇论文的被引用数&#xff0c;它实际上是某刊在某年被全部源刊物引证该刊前两年发表论文的次数&#xff0c;与该刊前两年所发表的全部源论文数之比。那么&#xff0c…

4.操作元素属性

4.1操作元素常用属性 ●通过 JS 设置/修改 标签元素属性&#xff0c;比如通过src更换图片 ●最常见的属性比如&#xff1a;href、 title、 src 等 ●语法: 对象.属性 值【示例】 // 1.获取元素 const pic document.querySelector( img ) // 2.操作元素 pic.src ./images/b…

vector使用

文章目录 vector的介绍vector的使用vector的初始化vector iterator迭代器的使用vector 空间增长问题vector的增删改查 迭代器失效总结 vector的介绍 文档介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着…

分布式事务及解决方案

1、分布式事务 分布式事务就是在一个交易中各个服务之间的相互调用必须要同时成功或者同时失败&#xff0c;保持一致性和可靠性。在单体项目架构中&#xff0c;在多数据源的情况下也会发生 分布式事务问题。本质上来说&#xff0c;分布式事务就是为了保证不同数据库的数据一致性…

关于Docker的知识点

Docker是一个快速交付应用、运行应用的技术。 Docker基本操作--容器 示例&#xff1a;创建运行一个Nginx容器

【每日一题】—— B - Broken Rounding(AtCoder Beginner Contest 273)

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…

【个人笔记】Linux命令之watch命令

1.命令简介 watch 以周期性方式执行给定的命令&#xff0c;并全屏显示执行结果&#xff0c;可以帮助监测一个命令的运行结果。 2.命令格式及参数选项说明 命令格式&#xff1a; watch [OPTIONS] COMMAND选项说明&#xff1a; -d, --differences [PERMANENT]高亮显示最近两…

Ventoy 使用教程图文详细版

文章目录 Ventoy 使用教程图文详细版简介安装 Ventoy下载 Ventoy安装到 U盘使用 Ventoy复制 ISO 文件启动电脑选择 ISO 文件结论Ventoy 使用教程图文详细版 简介 Ventoy 是一款开源的 U盘 启动工具,设计用于简化从 U盘 启动操作系统的过程。其主要特点是支持直接使用 ISO 文…