哈希应用——位图(bitset)

news2025/1/11 1:42:03

目录

见见猪跑(初步了解位图)

 位图的模拟实现

位图的应用

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

2、给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集? 

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

哈希切分

给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址? 与上题条件相同,如何找到top K的IP?

布隆过滤器

应用场景

布隆过滤器的删除

实现代码


 

见见猪跑(初步了解位图)

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

关键字:无符号整数。既然是一个整数,那么40亿个,存储就是一个麻烦的事。

根据我们所学:

只存储就需要16G,显然是不合理的,因此我们使用位图来很好的解决了这个问题。

 我们已知最小的存储单位是比特,一个比特位可以表示1或0两种状态。我们使1代表存在,0代表不存在。这样的话40亿数据只需要40亿个比特位,一共只需要0.5G,非常好用。

并且将我们需要处理的数据一一映射进每一个比特位上面。

每一个8比特位的空间我们以一个两个字节的char来开辟。

 位图的模拟实现

class bitset
{
public:
	//构造函数赋初值
	bitset()
	{
		//_bits.resize((N >> 3) + 1, 0);
		//开辟大小,并初始化为0
		_bits.resize(N / 8 + 1, 0);
	}

	//插入
	void set(size_t x)
	{
		//i在_bits去找在第几个char里面
		size_t i = x / 8;
		//j在char中去找在第几个位(bit)里面
		size_t j = x % 8;

		//将对应位置1
		_bits[i] |= (1 << j);
	}
	//删除
	void reset(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;

		//将所在位置0
		_bits[i] &= (~(1 << j));

	}
	//检查
	bool test(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;
		//若在该位有值(为1)则返回的就是非0的
		return _bits[i] & (1 << j);
	}

private:
	vector<char> _bits;
};


void test_bit_set()
{
	//bitset<100> bs1;
	// 
	//开辟了42亿的空间
	//
	bitset<-1> bs2;
	//bitset<0xffffffff> bs2;

	bs2.set(100);
	cout << bs2.test(10) << endl;
	cout << bs2.test(100) << endl;
	bs2.set(9999);
	cout << bs2.test(9999) << endl;
}

位图的应用

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

 解析:

“100亿整数”当我们看到这种字眼,首先直接将这些数据存储到整型里面是不现实的,因此要用到位图。然后我们看到需要找出只出现一次的整数,我们之前的位图只能表示一种状态,就是再或者不在,那么如何才能表示多种状态呢,我们想到了再使用一个位图。

#pragma once
//
//注意:
//无论给定多少个数据我们无符号整型范围最大也就到4294967295--2^32
namespace mwb
{
	template<size_t N>
	class bitset
	{
	public:
		//构造函数赋初值
		bitset()
		{
			//_bits.resize((N >> 3) + 1, 0);
			//开辟大小,并初始化为0
			_bits.resize(N / 8 + 1, 0);
		}

		//插入
		void set(size_t x)
		{
			//i在_bits去找在第几个char里面
			size_t i = x / 8;
			//j在char中去找在第几个位(bit)里面
			size_t j = x % 8;

			//将对应位置1
			_bits[i] |= (1 << j);
		}
		//删除
		void reset(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;

			//将所在位置0
			_bits[i] &= (~(1 << j));

		}
		//检查
		bool test(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			//若在该位有值(为1)则返回的就是非0的
			return _bits[i] & (1 << j);
		}

	private:
		vector<char> _bits;
	};


	

	template<size_t N>
	class twobitset
	{
	public:
		twobitset() {}

		void set(size_t x)
		{
			//插入前的状态
			if (!_bs1.test(x) && !_bs2.test(x))//00
			{
				_bs2.set(x);//01
			}
			else if (!_bs1.test(x) && _bs2.test(x))//01
			{
				_bs1.set(x);//1
				_bs2.reset(x);//0     // 10
			}
			// 如果本来就是 10  那么后边再插入都是10
		}
		void PrintOnce()
		{
			for (size_t i = 0; i < N; i++)
			{
				if (!_bs1.test(i) && _bs2.test(i))
				{
					cout << "只出现一次的数:" << i << endl;
				}
			}
			cout << endl;
		}
	public:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};
	void test_twobitset()
	{
		twobitset<100> tbs;
		int a[] = { 3,5,6,7,8,9,33,55,67,3,3,3,5,9,33 };
		//首先把每个数都set进去
		for (auto e : a)
		{
			tbs.set(e);
		}
		tbs.PrintOnce();
	}
}

2、给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集? 

        和第一问类似,开两个位图,分别将两组数据映射进位图,两个位图对应的比特位均为1即为交集。

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

        同第一问,开两个位图,00代表不存在,01代表出现一次,10代表出现两次,11代表出现两次以上。

哈希切分

给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址? 与上题条件相同,如何找到top K的IP?

通过哈希映射的方式可以将相同的IP放进同一个哈希桶里面,然后再使用map。

注意:很可能相同的比较多(数据量大),会导致map不能用。这样我们需要递归再次哈希映射。

布隆过滤器

布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。它是用多个哈希函数,将一个数据映射到位图结构中,可以用来告诉你 “某样东西一定不存在或者可能存在”。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。

 通过图中有一处两个元素映射到了同一个位置,我们也可以发现一点。当我们判断一个元素是否在时是不准确的,但是我们要去判断是否不在是准确的。

那么通过如何做法可以提高我们的准确率呢?这跟我们点外卖需要看好拼多的店的做法是一样的,我们就把这个值去映射多个位置(使用不同的哈希映射函数)然后判断这个值在不在的时候分别检查这几个位置,通过多个映射位置来确定这个值是否存在。

注意:可惜的是我们只能降低误判率,但不能完全消除误判。

应用场景

比如我们在玩游戏的时候需要注册的ID,我们就可以利用布隆过滤器首先对你输入的ID名字进行过滤。(因为布隆过滤器具有优秀的判重能力)。这样就可以在这些数据进入数据库之前进行一个很好的过滤,也减轻了在数据库中比对的负担。增加了效率。

布隆过滤器的删除

我们在布隆过滤器中删除的时候需要注意的是,当一个比特位同时被两个数据映射的时候就要小心了。如果我们因为需要删除其中的某一个数据,将这个比特位给置0了那么另一个数据必将收到影响。因此如果我们真的需要删除数据,在我们在布隆过滤器映射数据的时候哦就要搞一个计数器,来对在这一位上一共映射了多少个数据进行计数,如果需要删除直接计数器-1即可。

实现代码

#pragma once
#include<bitset>
namespace mwb
{
	struct BKDRHash
	{
		size_t operator()(const string& key)
		{
			size_t hash = 0;
			for (auto ch : key)
			{
				hash *= 131;
				hash += ch;
			}
			return hash;
		}
	};

	struct APHash
	{
		size_t operator()(const string& key)
		{
			unsigned int hash = 0;
			int i = 0;

			for (auto ch : key)
			{
				if ((i & 1) == 0)
				{
					hash ^= ((hash << 7) ^ (ch) ^ (hash >> 3));
				}
				else
				{
					hash ^= (~((hash << 11) ^ (ch) ^ (hash >> 5)));
				}

				++i;
			}

			return hash;
		}
	};

	struct DJBHash
	{
		size_t operator()(const string& key)
		{
			unsigned int hash = 5381;

			for (auto ch : key)
			{
				hash += (hash << 5) + ch;
			}

			return hash;
		}
	};

	struct JSHash
	{
		size_t operator()(const string& s)
		{
			size_t hash = 1315423911;
			for (auto ch : s)
			{
				hash ^= ((hash << 5) + ch + (hash >> 2));
			}
			return hash;
		}
	};











	template<size_t N,
		size_t X = 6,
		class K = string,
		class HashFunc1 = BKDRHash,
		class HashFunc2 = APHash,
		class HashFunc3 = DJBHash,
		class HashFunc4 = JSHash>

		class BloomFilter
	{
	public:
		void set(const K& key)
		{
			size_t hash1 = HashFunc1()(key) % (X * N);
			size_t hash2 = HashFunc2()(key) % (X * N);
			size_t hash3 = HashFunc3()(key) % (X * N);
			size_t hash4 = HashFunc4()(key) % (X * N);

			_bs.set(hash1);
			_bs.set(hash2);
			_bs.set(hash3);
			_bs.set(hash4);
		}

		bool test(const K& key)
		{

			size_t hash1 = HashFunc1()(key) % (X * N);
			if (!_bs.test(hash1))
			{
				return false;
			}
			size_t hash2 = HashFunc1()(key) % (X * N);
			if (!_bs.test(hash2))
			{
				return false;
			}
			size_t hash3 = HashFunc1()(key) % (X * N);
			if (!_bs.test(hash3))
			{
				return false;
			}
			size_t hash4 = HashFunc1()(key) % (X * N);
			if (!_bs.test(hash4))
			{
				return false;
			}


			//前面判断都是准确,不存在误判
			//可能存在误判,映射几个位置都冲突,就会误判
			return true;


		}
	private:
		std::bitset<N * X> _bs;
	};

	void test_bloomfilter1()
	{
		string str[] = { "猪八戒", "孙悟空", "沙悟净", "唐三藏", "白龙马1","1白龙马","白1龙马","白11龙马","1白龙马1" };
		BloomFilter<10> bf;
		for (auto& str : str)
		{
			bf.set(str);
		}

		for (auto& s : str)
		{
			cout << bf.test(s) << endl;
		}
		cout << endl;

		srand(time(0));
		for (const auto& s : str)
		{
			cout << bf.test(s + to_string(rand())) << endl;
		}
	}
}

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

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

相关文章

第六章 Gated RNN

目录6.1 RNN的问题6.1.1 RNN的复习6.1.2 梯度消失和梯度爆炸6.1.3 梯度消失和梯度爆炸的原因6.1.4 梯度爆炸的对策6.2 梯度消失和LSTM6.2.1 LSTM的接口6.2.2 LSTM层的结构6.2.3 输出门6.2.4 遗忘门6.2.5 新的记忆单元6.2.6 输入门6.2.7 LSTM的梯度的流动6.3 LSTM的实现6.4 使用…

CIO成就计划第二季第一期 | 活动回顾:基于数字技术重塑流程,驱动业务增长

2023年3月25日&#xff0c;《科创人》联手金蝶共同打造的【CIO成就计划第二季】首期培训在北京金蝶软件园圆满举行。 【CIO成就计划】第二季&#xff0c;坚持服务于企业CIO、数字化变革负责人的价值定位&#xff0c;通过三期线下闭门培训会社群交流&#xff0c;帮助CIO建立应对…

JUC高级十-AbstractQueuedSynchronizer之AQS

1. 前置知识 公平锁和非公平锁可重入锁自旋锁LockSupport数据结构之双向链表设计模式之模板设计模式 AQS重要性 JAVA ------>JVM AQS ------>AQS 2. AQS入门级别理论知识 2.1 是什么? 2.1.1 字面意思 Abstract Queued Synchronizer----抽象的队列同步器 源码位置: …

【Java 并发编程】一文读懂线程、协程、守护线程

一文读懂线程、协程、守护线程1. 线程的调度1.1 协同式线程调度1.2 抢占式线程调度1.3 设置线程的优先级2. 线程的实现模型和协程2.1 内核线程实现2.2 用户线程实现2.3 混合实现2.4 Java 线程的实现2.5 协程2.5.1 出现的原因2.5.2 什么是协程2.5.3 Java19 虚拟线程 - 协程的复苏…

Cat原理简析

Cat原理简析 链路追踪系统设计思路如何高效组织业务日志如何动态串联业务日志通用解决方案链路定义链路染色链路上报链路存储 Cat原理客户端原理API设计序列化和通信客户端埋点核心类分析流程分析启动流程:消息生产Context 线程本地变量Transaction事务的开启其他类型消息组合关…

网页设计方向有哪些SCI期刊推荐? - 易智编译EaseEditing

网页设计和开发方向主要涉及人机交互、用户体验、可访问性等方面&#xff0c;以下是几个相关的SCI期刊推荐&#xff1a; ACM Transactions on Computer-Human Interaction (ACM TOCHI)&#xff1a; 该期刊由ACM&#xff08;Association for Computing Machinery&#xff09;出…

一次etcd变更引发的惨案

问题描述 在做etcd的数据变更时候&#xff0c;etcd在组成集群的时候出现leader不断切换问题&#xff0c;导致集群不稳定&#xff0c;都面将不健康的etcd节点踢出&#xff0c;只剩etcd单节点&#xff0c;后面将踢出的etcd节点重新加入现有etcd&#xff0c;导致etcd集群奔溃&…

【java踩坑搞起】MybatisPlus封装的mapper不支持 join,那咋办

众所周知&#xff0c;Mybatis Plus 封装的 mapper 不支持 join&#xff0c;如果需要支持就必须自己去实现。但是对于大部分的业务场景来说&#xff0c;都需要多表 join&#xff0c;要不然就没必要采用关系型数据库了。 直到前几天&#xff0c;偶然碰到了这么一款叫做mybatis-p…

权限提升:网站后台.(提权思路.)

权限提升&#xff1a;网站后台 权限提升简称提权&#xff0c;由于操作系统都是多用户操作系统&#xff0c;用户之间都有权限控制&#xff0c;比如通过 Web 漏洞拿到的是 Web 进程的权限&#xff0c;往往 Web 服务都是以一个权限很低的账号启动的&#xff0c;因此通过 Webshell …

Form Designer V2发布

基于Ant Design 和 jQuery UI 的表单设计器 github 地址 特性 React Vue 3.x Typescript 统一的组件定义&#xff0c;对Vue 和React 的实现提供一个统一的组件定义描述 概念 Component 组件Layout 布局&#xff0c;一种特殊的ComponentComponent Editor 组件属性编辑器Comp…

【开发日志】2023.04 ZENO----Composite----CompImport、ReadImageFlie

CompImport TEST&#xff1a; 用ParticlesWrangle创造属性A(紫色&#xff09;&#xff0c;B&#xff08;青色&#xff09; &#xff0c;用CompImport结点将属性转化为图片输入到Composite3进行合成 Input&#xff1a; Output: /* 导入地形网格的属性&#xff0c;可能会有多个属…

Docker安装 docker-registry 镜像仓库

一、运行如下命令安装docker-registry镜像仓库&#xff1a; docker run -d \ -p 5000:5000 \ -v /usr/local/registry:/var/lib/registry \ --restartalways \ --name registry \ registry:2 二、测试镜像生成并推送到镜像仓库 1、新建一个目录 mkdir target 2、上传一…

Taro+Vue3 小程序引入echarts表

背景&#xff1a;根据需求在一个报告界面需要展示不同的echarts表来使数据更友好的显示。 效果如下&#xff1a; 一.taro支持echarts 官方说明&#xff1a;Taro 文档支持引用小程序端第三方组件库 物料文档&#xff1a;Taro 物料市场 | 让每一个轮子产生价值 二.引入echart…

Qt5.12實戰之Linux靜態庫編譯與調用完整過程

1.安裝gedit sudo apt-get install gedit -y 2.使用gedit編輯靜態庫源文件test.cpp gedit test.cpp 輸入下面內容 &#xff1a; #include <stdio.h> int func() {return 888; } 如下圖操作&#xff1a; 保存test.cpp並編譯 爲目標文件 gcc -c test.cpp如下圖示&am…

【剑指 Offer】(1)

文章目录前言一、 数组中重复的数字:fire: 解决方法:dog: 代码二、二维数组中的查找:fire:思路:dog:代码三、替换空格:fire:思路:dog: 代码四、从尾到头打印链表:fire:思路:dog:代码:dog: 代码五、重建二叉树:fire:思路:dog: 代码总结前言 剑指offer系列是一本非常著名的面试题…

【BUG SHOW】一个由高并发引起的缺陷分析

软件质量保障: 所寫即所思&#xff5c;一个阿里质量人对测试的所感所悟。 缺陷介绍 平台有这样的两个功能&#xff1a; ​功能01: 用户发起支付&#xff0c;成功则将表pay单据状态推进SUCCESS&#xff0c;然后发出支付结果消息&#xff1b;反之如果支付失败&#xff0c;则状态…

vue 报错 error:03000086:digital envelope routines::initialization error解决方案

目录 1. 引言: 2. 更换版本出现问题: 3. 出现原因: 4. 解决办法: -> 4. 1 删了 再换回16.15版本 -> 4.2 指令修改(好使) ---> 4.2.1效果如图 -> 4.3 其他指令就别试了 压根不好使 1. 引言: npm出现问题 , 卸载后 装了个新node 18.15版本 2. 更换版本…

Servlet-搭建个人博客系统(MVC架构模式简介,maven的配置和使用)

目录 1. MVC架构模式简介 2. maven的配置和使用 3. 项目总述&#x1f43b; 3.1 &#x1f34e;Controller层 3.2 &#x1f34e;Model层 3.3 &#x1f34e;View层 4. 页面的主要功能实现&#x1f43b; 4.1 &#x1f34e;登陆页面&#xff08;login.html&#xff09; 4.2…

Oracle Recovery Tools快速恢复断电引起的无法正常启动数据库----惜分飞

由于异常断电,数据库启动报错ORA-01113和ORA-01110&#xff0c;ORA-00322和ORA-00312以及ORA-00314和ORA-00312错误 Mon Apr 17 09:35:04 2023 ALTER DATABASE OPEN Errors in file D:\APP\ADMINISTRATOR\diag\rdbms\orcl\orcl\trace\orcl_ora_10192.trc: ORA-01113: 文件 1 需…

史上最牛二分查找,不服来战

&#x1f929;本文作者&#xff1a;大家好&#xff0c;我是paperjie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 &#x1f970;内容专栏&#xff1a;这里是《算法详解》&#xff0c;笔者用重金(时间和精力)打造&#xff0c;将算法知识一网打尽&#xff0c;希望可以…