C++位图和布隆过滤器

news2024/11/30 0:35:58

📟作者主页:慢热的陕西人

🌴专栏链接:C++

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

本博客主要内容介绍C++中的位图和布隆过滤器模拟实现和简单的应用

文章目录

  • C++位图和布隆过滤器
    • Ⅰ. 位图
      • Ⅰ. Ⅰ 位图的概念
      • Ⅰ. Ⅱ位图的简易实现
      • Ⅰ. Ⅲ位图的应用
    • Ⅱ.布隆过滤器
      • Ⅱ. Ⅰ 布隆过滤器的提出
      • Ⅱ. Ⅱ布隆过滤器的概念
      • Ⅱ. Ⅲ布隆过滤器的模拟实现
      • Ⅱ. Ⅳ 布隆过滤器的应用

C++位图和布隆过滤器

Ⅰ. 位图

Ⅰ. Ⅰ 位图的概念

  • 位图的概念

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

面试题:

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在 这40亿个数中。【腾讯】

要求:

​ 1.遍历,时间复杂度O(N)

​ 2.排序(O( N l o g N N log N NlogN)), 二分查找O( l o g N logN logN)

​ 3.位图来解决

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

image-20230923162854557

Ⅰ. Ⅱ位图的简易实现

	template<size_t N>
	class bitset
	{
        //构造函数
		bitset()
		{
			_bit = new vector<char>(N / 8 + 1);
			_bit_count = 
		}
		//将x位反置位
		void reset(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			_bit[i] &= ~(1 << j);
		}
		//将x置位
		void set(size_t x)
		{
			size_t i = x / 8; // 计算x在第i个char内
			size_t j = x % 8;// 计算x在char的第j个位置
			_bit[i] |= (1 << j);
		}
		//查看x是否存在
		bool test(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			return _bit[i] & (1 << j);
		}

	private:
		vector<char> _bit;
	};

Ⅰ. Ⅲ位图的应用

  1. 给定100亿个整数,设计算法找到只出现一次的整数?

    	template<size_t N>
    	class twobit
    	{
    	public:
    		void set(int x)
    		{
    			//00
    			if (set1.test(x) == false && set2.test(x) == false)
    			{
    				set2.set(x);
    			}
    			//01
    			else if (set1.test(x) == false && set2.test(x) == true)
    			{
    				set2.reset(x);
    				set1.set(x);
    			}
    		}
    		void Print()
    		{
    			for (int i = 0; i < N; ++i)
    			{
    				if (set1.test(i) == false && set2.test(i) == true)
    					cout << i << " ";
    			}
    		}
    
    	public:
    		bitset<N> set1;
    		bitset<N> set2;
    	};
    
    	void twobittest()
    	{
    		int a[] = { 3, 45,12, 12, 43,55,12,67,98,67,35,86 };
    		twobit<100> set;
    		for (auto& i : a)
    		{
    			set.set(i);
    		}
    		set.Print();
    	}
    
  2. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

    ①将第一个文件的所有整数存入到一个位图中。

    然后遍历第二个文件查看是否在位图中?

    如果在位图中,将位图中的这个整数reset,并记录当前的整数

    ②将两个文件的所有整数,分别存储到两个位图中

    再将两个位图按位与运算即可得到结果

  3. 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

    对1题进行改造

    template<size_t N>
    	class twobit
    	{
    	public:
    		void set(int x)
    		{
    			//00
    			if (set1.test(x) == false && set2.test(x) == false)
    			{
    				set2.set(x);
    			}
    			//01
    			else if (set1.test(x) == false && set2.test(x) == true)
    			{
    				set2.reset(x);
    				set1.set(x);
    			}
    			//10
    			else if (set1.test(x) == true && set2.test(x) == false)
    			{
    				set2.set(x);
    			}
    		}
    		void Print()
    		{
    			for (int i = 0; i < N; ++i)
    			{
    				if ((set1.test(i) == true && set2.test(i) == false) || (set1.test(i) == false && set2.test(i) == true))
    					cout << i << " ";
    			}
    		}
             
    	public:
    		bitset<N> set1;
    		bitset<N> set2;
    	};
             
    	void twobittest()
    	{
    		int a[] = { 3, 45,12, 12, 43,55,12,67,98,67,35,86 };
    		twobit<100> set;
    		for (auto& i : a)
    		{
    			set.set(i);
    		}
    		set.Print();
    	}
    

位图的优点:

速度快,占用空间小

位图的缺点:

只能映射整型,浮点数,string不能映射

因此我们引入布隆过滤器

Ⅱ.布隆过滤器

Ⅱ. Ⅰ 布隆过滤器的提出

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

1.用哈希表存储用户记录,缺点:浪费空间

2.用位图存储用户记录,缺点:位图一般只能处理整形,如果内容编号是字符串,就无法处理了。

3.将哈希与位图结合,即布隆过滤器

Ⅱ. Ⅱ布隆过滤器的概念

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

image-20230923180148387

布隆过滤器的详细介绍:https://zhuanlan.zhihu.com/p/43263751/

Ⅱ. Ⅲ布隆过滤器的模拟实现

struct BKDRHash
	{
		size_t operator()(const string& s)
		{
			// BKDR
			size_t value = 0;
			for (auto ch : s)
			{
				value *= 31;
				value += ch;
			}
			return value;
		}
	};


	struct APHash
	{
		size_t operator()(const string& s)
		{
			size_t hash = 0;
			for (long i = 0; i < s.size(); i++)
			{
				if ((i & 1) == 0)
				{
					hash ^= ((hash << 7) ^ s[i] ^ (hash >> 3));
				}
				else
				{
					hash ^= (~((hash << 11) ^ s[i] ^ (hash >> 5)));
				}
			}
			return hash;
		}
	};
	struct DJBHash
	{
		size_t operator()(const string& s)
		{
			size_t hash = 5381;
			for (auto ch : s)
			{
				hash += (hash << 5) + ch;
			}
			return hash;
		}
	};



	template<size_t N, class K,
	class Hash1 = BKDRHash,
	class Hash2 = APHash,
	class Hash3 = DJBHash>
	class BloomFilter
	{
        //向布隆过滤器中插入元素
		void set(const K& key)
		{
			size_t hash1 = Hash1()(key) % N;
			_bs.set(hash1);
			size_t hash2 = Hash2()(key) % N;
			_bs.set(hash2);
			size_t hash3 = Hash3()(key) % N;
			_bs.set(hash3);
		}

		//检查是否存在于布隆过滤器中
		bool test(const K& key)
		{
			size_t hash1 = Hash1()(key) % N;
			if (!_bs.test(hash1))
			{
				return false;
			}
			size_t hash2 = Hash2()(key) % N;
			if (!_bs.test(hash2))
			{
				return false;
			}
			size_t hash3 = Hash3()(key) % N;
			if (!_bs.test(hash3))
			{
				return false;
			}
			//一个不确定的true
			return true;
		}

	private: 
		bitset<N> _bs;
	};

}

Ⅱ. Ⅳ 布隆过滤器的应用

1.给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出 精确算法和近似算法

首先我们分析:

对于100亿个query(query可以认为是一个字符串),我们估计每个query平均的大小为50byte,那么100亿个query就是500亿byte,也就是大约500G。

对于这么庞大的数据量我们肯定不能全部放到内存中去计算,所以我们要想办法将他们分割

image-20231004195344284

但是如上的操作也会产生问题:

因为不是平均的分割,可能出现冲突多,每个Ai,Bi文件过大。----假设两个都是4-5G的情况

出现这两种的情况的两个原因:

①单个文件中有大量的重复query

②单个文件中有大量的不重复query

那么我们具体如何操作呢?

直接用unordered_set/set,依次读取query,每次插入到set中。

①如果读取整个小文件中的query,都可以成功插入set,那么说明情况1;

②如果读取的整个小文件query,插入过程中出现了抛异常的情况,则是情况2。这时候我们可以选择换其他的哈希函数,再次分割,在求交集。

**说明:**set插入key的时候,set中存在的话就会返回false,如果内存不够的话,就会抛bad_alloc的异常,剩下的都是成功插入。

2.如何扩展BloomFilter使得它支持删除元素的操作?

我们可以采用多个位去统计出现的次数。

**3.哈希切割:给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址? **

与上题条件相同,如何找到top K的IP?如何直接用Linux系统命令实现?

image-20231004212225081

对于第二问我们可以建立一个有k个元素的小堆,将文件中的IP地址向堆中插入我们就可以得到topK。

到这本篇博客的内容就到此结束了。
如果觉得本篇博客内容对你有所帮助的话,可以点赞,收藏,顺便关注一下!
如果文章内容有错误,欢迎在评论区指正

在这里插入图片描述

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

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

相关文章

求直角三角形第三点的坐标

文章目录 求直角三角形第三点的坐标1. 原理2. 数学公式3. 推导过程 求直角三角形第三点的坐标 1. 原理 已知内容有&#xff1a; P1、P2 两点的坐标&#xff1b; dis1 为 P1与P2两点之间的距离&#xff1b; dis2 为 P2与P3两点之间的距离&#xff1b; 求解&#xff1a; …

10、网络防火墙的设置

1、查看防火墙是否开启 systemctl status firewalld 此图表示防火墙已开启&#xff0c;如果未开启可使用systemctl start firewalld开启 2、查看已开启的端口 firewall-cmd --list-ports 默认无打开的端口 3、打开80端口 firewall-cmd --zonepublic --add-port80/tcp --p…

stm32备份

存储器的分类&#xff1a; 存储器首先根据断电后存储的数据是否会丢失&#xff0c;可以分为易失存储器和非易失存储器&#xff0c;易失存储器主要应用于内存&#xff0c;非易失存储器主要用于外存。 易失存储器以RAM随机存储器为代表&#xff0c;随机的含义是存储器中的数据读取…

EfficientDet: Scalable and Efficient Object Detection

CVPR2020 V7 Mon, 27 Jul 2020 引用量&#xff1a;243 机构&#xff1a;Google 贡献&#xff1a;1>提出了多尺度融合网络BiFPN 2>对backbone、feature network、box/class prediction network and resolution进行复合放缩&#xff0c;有着不同的…

Linux第4章-目录结构

引子 在Linux中&#xff0c;一切皆文件&#xff01;&#xff01;&#xff01; 在Linux中&#xff0c;一切皆文件&#xff01;&#xff01;&#xff01; 在Linux中&#xff0c;一切皆文件&#xff01;&#xff01;&#xff01; 基本介绍 1.Linux的文件系统&#xff0c;是采用…

LoRA 是如何工作的?

概述 纯笔记 LoRA的原理 LoRA其实是对稳定扩散模型最关键的部分进行了微小的改变。 这个关键的部分叫&#xff1a;cross-attention layers – 交叉注意力层。 研究人员发现&#xff0c;对这关键部分进行微调就足以实现良好的训练。 上面黄色部分&#xff0c;QKV 部分就是&a…

Python进阶之迭代器

文章目录 前言一、迭代器介绍及作用1.可迭代对象2. 迭代器 二、常用函数和迭代器1.常用函数2.迭代器 三、总结结束语 &#x1f482; 个人主页:风间琉璃&#x1f91f; 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联系博主&#x1f4ac; 如果文章对你有帮助、欢迎关注…

ELK 日志分析系统介绍与部署

目录 一、ELK 简介: 1.开源工具介绍&#xff1a; 2.其它组件&#xff1a; 2.1 Filebeat&#xff1a; 2.2 Fluentd&#xff1a; 2.3 缓存/消息队列&#xff08;redis、kafka、RabbitMQ等&#xff09;&#xff1a; 3. filebeat 结合 logstash 带来好处&#xff1a; 二、为什么要…

zookeeper源码学习笔记(一)

一、缘起 1、CP还是AP 作为一个在大数据行业工作了7&#xff5e;8年的老兵&#xff0c;在被问到zookeeper和CAP时&#xff0c;竟然有些恍惚&#xff0c;AP还是CP&#xff1f; 看了一些博文&#xff0c;答案几乎都是CP&#xff1f; zookeeper的实现中&#xff0c;P是一定的&…

【C语言】.c源文件从编译到链接生成可执行程序的过程

本篇文章目录 1. 过程概览2. 编译与链接2.1 预编译/预处理2.2 编译2.3 汇编2.4 链接 3. 执行/运行环境 1. 过程概览 编译到链接是c语言的翻译环境&#xff0c;c语言还有执行环境。 组成一个程序的每个源文件通过编译过程分别转换成目标代码&#xff08;object code&#xff09;…

推荐《一拳超人》

《一拳超人》是ONE原作&#xff0c;村田雄介作画&#xff0c;连载于网络漫画杂志《邻座的Young jump》上的漫画。 [1] 原为ONE在个人网站上连载的练笔之作&#xff0c; [2] 后被喜爱该作的另一漫画家村田雄介在征得ONE同意后重新绘制而成。 简体中文电子版由哔哩哔哩漫画发布…

JavaSE学习值之--认识异常

&#x1f495;"有效知识的前提是承认知识边界&#xff0c;承认我们对边界那边的一切无可奉告。"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;JavaSE学习值之--认识异常 一.什么是异常&#xff1f; 异常就是程序在运行的时候产生的不正常的行为 …

java_Stream API

文章目录 一、Stream API vs 集合二、Stream 使用的执行流程2.1、创建Stream2.1、中间操作2.1.1. filter2.1.2. limit2.1.3. skip2.1.4. distinct2.1.5. map2.1.6. sorted 一、Stream API vs 集合 Stream API 关注的是多个数据的计算&#xff08;排序、查找、过滤、映射、遍历…

网络工程师知识点4

51、OSPF的LSA类型 52虚链路&#xff1a;作用 解决区域划分不合理的问题 通过建立虚拟链路来实现一般区域与骨干区域的理论化直连 54、NSSA区域的特点 1、可以学习本区域连接的外部路由 2、不学习其他区域转发进来的外部路由 3、与外部区域通信使用ABR自动产生的默认路…

python:爬取网络小说,看这一篇就够了

说明&#xff1a; 本教程仅供于学习研究使用&#xff0c;请勿用于其他用途。 软件安装&#xff1a; 官网下载visual studio Visual Studio: 面向软件开发人员和 Teams 的 IDE 和代码编辑器 (microsoft.com) 点进网页后下拉找到个人免费版本。点击下载即可。 1&#xff1a;找到…

第六章:TF-A学习

TF-A学习 TF-A初探如何获取系统源码移植过程中遇到的问题和解决方案编译报错&#xff1a;arm-none-linux-gnueabi-gcc: not foundTF-A 源码打补丁 遇到assume -R&#xff1f;[n] TF-A初探 为了保证安全 ARM 推出了 Arm Trusted Firmware 的可信固件&#xff0c;简称 TF-A。它…

windows环境cmake的nmake failed

windows环境cmake异常 问题如下&#xff1a; > cmake ..CMake Error at CMakeLists.txt:4 (PROJECT): Running nmake -?failed with:系统找不到指定的文件。CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage CMake Error: CMAKE_CXX_COMPILER not set, after…

中断机制-interrupt和isInterrupted源码分析、中断协商案例

当前线程的中断标识为true&#xff0c;是不是线程就立刻停止&#xff1f; 答案是不立刻停止&#xff0c;具体来说&#xff0c;当对一个线程&#xff0c;调用interrupt时&#xff1a; 如果线程处于正常活动状态&#xff0c;那么会将该线程的中断标志设置为true&#xff0c;仅此…

【C++】:关键字 命名空间 输入输出 缺省参数 函数重载 引用

【本节目标】 C关键字命名空间C输入&输出缺省参数函数重载引用 C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式等 熟悉C语言之后&#xff0c;对C学习有一定的帮助&#xff0c;本章节主要目标&#xff…

关于面试以及小白入职后的一些建议

面试的本质 面试的过程是一个互相选择的过程&#xff1b;面试官的诉求是&#xff0c;了解应聘者的个人基本信息、工作态度、专业能力及其他综合能力是否与公司招聘岗位匹配&#xff1b;面试者的诉求是&#xff0c;拿下招聘岗位offer&#xff0c;获得工作报酬&#xff1b; 面试…