深入浅出C++ ——哈希的应用

news2024/12/26 11:52:48

文章目录

  • 一、位图
    • 1. 位图的概念
    • 2. STL中的位图
    • 3. 位图的特点
    • 4. 位图的应用
    • 5. 位图的实现
    • 6. 位图的使用
  • 二、布隆过滤器
    • 1. 布隆过滤器提出
    • 2. 布隆过滤器概念
    • 3. 布隆过滤器的设计思路
    • 4. 布隆过滤器的插入
    • 5. 布隆过滤器的查找
    • 6. 布隆过滤器删除
    • 7. 布隆过滤器的优缺点
    • 8. 布隆过滤器的实现
    • 9. 布隆过滤器的使用


一、位图

1. 位图的概念

    所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。 数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。例如:

在这里插入图片描述


2. STL中的位图

     STL提供了bitset容器供用户使用,其中常用的函数接口如下所示。

函数名称函数作用
bitset();构造一个空的位图
set(size_t pos)将pos位置的bit位设置为1
reset(size_t pos)将pos位置的bit位设置为0
reset(size_t pos)返回pos位置bit位的结果

     其中每一个位置pos对应一个整型数字。STL库中的bitset是用数组实现的,而不是vector。所以如果操作大量数据的时候,可以在堆上new一个bitset,避免栈溢出。


3. 位图的特点

     位图速度快,省时间,采用直接定址法,不存在哈希冲突。但是位图相对局限,只能映射处理整形。


4. 位图的应用

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

5. 位图的实现

template<size_t N>
class bitset
{
public:
	bitset()
	{
		_bits.resize(N / 8 + 1, 0);
	}

	//将对应的比特位置为1
	void set(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;
		_bits[i] |= (1 << j);
	}

	//将对应的比特位置为0
	void reset(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;
		_bits[i] &= ~(1 << j);
	}

	//判断值在不在
	bool test(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;
		return _bits[i] & (1 << j);  //不是&=,只是&
	}

private:
	vector<char> _bits;
};

void test_set()
{
	bitset<-1> bs1;
	//bitset<0xffffffff> bs2;
	bs1.set(8);
	bs1.set(9);
	bs1.set(20);

	cout << bs1.test(8) << endl;
	cout << bs1.test(9) << endl;
	cout << bs1.test(20) << endl;

	bs1.reset(8);
	bs1.reset(9);
	bs1.reset(20);

	cout << bs1.test(8) << endl;
	cout << bs1.test(9) << endl;
	cout << bs1.test(20) << endl;
}

6. 位图的使用

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

     40亿个整数,在内存中占用大约16G空间,使用搜索树和哈希表都不行,因为内存中存储不了。可以使用外排序+二分查找,但是因为数据太大,只能放到磁盘文件中,要进行大量的IO,效率低。这里最好使用位图解决,只需要512MB就可以解决。


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

     使用kv的统计次数搜索模型,使用两个bitset,表示一个数是否在可以分为三种情况,0次可以用00表示,1次可以用01表示,2次及以上可以用10表示。

template<size_t N>
class twobitset
{
public:
	void set(size_t x)
	{
		bool inset1 = _bs1.test(x);
		bool inset2 = _bs2.test(x);
		// 00
		if (inset1 == false && inset2 == false)
		{
			// -> 01
			_bs2.set(x);
		}
		else if (inset1 == false && inset2 == true)
		{
			// ->10
			_bs1.set(x);
			_bs2.reset(x);
		}

		else if (inset1 == true && inset2 == false) //三次及其以上
		{
			// ->11
			_bs1.set(x);
			_bs2.set(x);
		}
	}

	void print_once_num()
	{
		for (size_t i = 0; i < N; ++i)
		{
			if (_bs1.test(i) == false && _bs2.test(i) == true)
			{
				cout << i << endl;
			}
		}
	}
private:
	bitset<N> _bs1;
	bitset<N> _bs2;
};

void test_bitset()
{
	int a[] = { 3, 4, 5, 2, 3, 4, 4, 4, 4, 12, 77, 65, 44, 4, 44, 99, 33, 33, 33, 6, 5, 34, 12 };
	twobitset<100> bs;
	for (auto e : a)
	{
		bs.set(e);
	}
	bs.print_once_num();
}

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

     这个问题也可以使用两个bitset,文件一的值映射和文件二的值映射分别存到两个bitset中,当两个映射位都是1的值就是交集。


(4)一个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整
数?

     这个问题是问题二的变形,使用两个bitset,表示一个数是否在可以分为四种情况,0次可以用00表示,1次可以用01表示,2次可以用10表示,三次及其以上使用11表示。


二、布隆过滤器

1. 布隆过滤器提出

     使用新闻客户端看新闻时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉那些已经看过的内容。新闻客户端推荐系统如何实现推送去重的?

     用服务器记录了用户看过的所有历史记录,当推荐系统推荐新闻时会从每个用户的历史记录里进行筛选,过滤掉那些已经存在的记录。用哈希表存储用户记录,会浪费空间。用位图存储用户记录,但是位图一般只能处理整形,如果内容编号是字符串,就无法处理了。这时就要使用布隆过滤器,将哈希与位图结合。


2. 布隆过滤器概念

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

在这里插入图片描述


3. 布隆过滤器的设计思路

     使用哈希算法将字符串转换成整形去映射一个位置来标记。理论而言,一个值映射的位越多,误判率越低,但是空间消耗越高。那么如何选择合适的布隆过滤器长度呢?有专家学者研究过,当插入一个元素的时候,开4.2个位是最合适的,整数倍近似为5


4. 布隆过滤器的插入

在这里插入图片描述


5. 布隆过滤器的查找

     布隆过滤器的思想是将一个元素用多个哈希函数映射到一个位图中,因此被映射到的位置的比特位一定为1。

    所以可以按照以下方式进行查找:分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个为零,代表该元素一定不在哈希表中,否则可能在哈希表中。

    布隆过滤器如果说某个元素不存在时,该元素一定不存在如果该元素存在时,该元素可能存在,因为有些哈希函数存在一定的误判。比如:在布隆过滤器中查找"alibaba"时,假设3个哈希函数计算的哈希值为:1、3、7,刚好和其他元素的比特位重叠,此时布隆过滤器告诉该元素存在,但实该元素是不存在的。


6. 布隆过滤器删除

     布隆过滤器不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素。 一种支持删除的方法是将布隆过滤器中的每个比特位扩展成一个小的计数器,插入元素时给k个计数器加一,删除元素时,给k个计数器减一,通过多占用几倍存储空间的代价来增加删除操作。


7. 布隆过滤器的优缺点

布隆过滤器优点

  1. 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关。
  2. 哈希函数相互之间没有关系,方便硬件并行运算。
  3. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势。
  4. 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势。
  5. 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能。
  6. 使用同一组散列函数的布隆过滤器可以进行交、并、差运算。

布隆过滤器缺陷

  1. 有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中(补救方法:再建立一个白名单,存储可能会误判的数据)。
  2. 不能获取元素本身。
  3. 一般情况下不能从布隆过滤器中删除元素。
  4. 如果采用计数方式删除,可能会存在计数回绕问题。

8. 布隆过滤器的实现

struct HashBKDR
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t val = 0;
		for (auto ch : key)
		{
			val *= 131;
			val += ch;
		}

		return val;
	}
};

struct HashAP
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t hash = 0;
		for (size_t i = 0; i < key.size(); i++)
		{
			if ((i & 1) == 0)
			{
				hash ^= ((hash << 7) ^ key[i] ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ key[i] ^ (hash >> 5)));
			}
		}
		return hash;
	}
};

struct HashDJB
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t hash = 5381;
		for (auto ch : key)
		{
			hash += (hash << 5) + ch;
		}

		return hash;
	}
};


// N表示准备要映射N个值
template<size_t N,
		class K = string, 
		class Hash1 = HashBKDR, 
		class Hash2 = HashAP, 
		class Hash3 = HashDJB>
class BloomFilter
{
public:
	void Set(const K& key)
	{
		size_t hash1 = Hash1()(key) % (_ratio * N);
		_bits->set(hash1);

		size_t hash2 = Hash2()(key) % (_ratio * N);
		_bits->set(hash2);

		size_t hash3 = Hash3()(key) % (_ratio * N);	
		_bits->set(hash3);
	}

	bool Test(const K& key)
	{
		size_t hash1 = Hash1()(key) % (_ratio * N);
		if (!_bits->test(hash1))
			return false; // 准确的

		size_t hash2 = Hash2()(key) % (_ratio * N);
		if (!_bits->test(hash2))
			return false; // 准确的

		size_t hash3 = Hash3()(key) % (_ratio * N);
		if (!_bits->test(hash3))
			return false;  // 准确的

		return true; // 可能存在误判
	}

private:
	const static size_t _ratio = 5;
	std::bitset<_ratio* N>* _bits = new std::bitset<_ratio* N>;
};

9. 布隆过滤器的使用

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

    可以把一个文件当中的query(字符串)放到一个布隆过滤器中去,在看另外一个在不在,存在误判,所以是近似算法。

    假设每个query占有30byte,那么100亿个query占用300G空间,很现实,内存放不下。精确算法是使用哈希切分
在这里插入图片描述


(2)给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?如何找到top K的IP?

    读取每个ip,i=Hash(ip)%500,这个ip就进入第i个小文件。相同的ip,一定进入了同一个小文件。使用map,依次对每个小文件统计次数,如果找topK,就建一个K个值为<ip,count>的小堆即可。


(3)如何扩展BloomFilter使得它支持删除元素的操作。

    布隆过滤器不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素。 一种支持删除的方法是将布隆过滤器中的每个比特位扩展成一个小的计数器,插入元素时给k个计数器加一,删除元素时,给k个计数器减一,通过多占用几倍存储空间的代价来增加删除操作,优势被削弱了,一般不会这几支持删除操作的布隆过滤器。

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

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

相关文章

div增加鼠标点透,css设置点击穿透

需求&#xff1a;将一张照片盖到一个div上面&#xff0c;但同时下面div上面的点击事件不受影响。 这样就需要用到 CSS 的鼠标穿透属性&#xff1a;pointer-events: none&#xff0c;下面主要对pointer-events属性的值做一个简单的介绍。 pointer-event的所有属性值: pointer…

计讯物联环保数采仪全系列产品为节能降耗减碳贡献绿色力量

政策背景 近日&#xff0c;工业和信息化部、国家发展改革委、生态环境部三部门联合印发《工业领域碳达峰实施方案》&#xff08;以下简称“方案”&#xff09;。《方案》提出&#xff0c;促进中小企业绿色低碳发展。优化中小企业资源配置和生产模式&#xff0c;探索开展绿色低…

在字节跳动,造赛博古籍

“你在字节跳动哪个业务&#xff1f;”“古籍数字化。把《论语》《左传》《道德经》这些古籍变成电子版&#xff0c;让大家都能免费看。”没错&#xff0c;除了你熟悉的那些 App&#xff0c;字节跳动还在做一些小众而特别的事情&#xff0c;古籍数字化就是其中之一。在字节跳动…

Python+Selenium4元素交互1_web自动化(5)

目录 0. 上节回顾 1. 内置的等待条件 2. 元素属性 1. Python对象属性 2. HTML元素属性 3. 元素的交互 1. 输入框 2. 按钮 3. 单选框和复选框 0. 上节回顾 DEBUG的方式&#xff1a;JS断点 Python断点编程语言提供的等待方式&#xff1a;sleepselenium提供的等待方式&…

CDGA|浅谈“以治促用,以用促治”的数据治理战略

数据治理夯实企业数字化转型基础。采取“以治促用&#xff0c;以用促治”的数据治理战略&#xff0c;可以充分释放了企业核心运行要素的活力。 “以治促用”是指通过建立在数据治理链路及用户多维评估系统的基础上&#xff0c;对数据资产重新进行价值识别&#xff0c;推进高价值…

30岁测试开发年薪不足50万,被面试官嘲讽混得太差?

近日&#xff0c;有网友发帖称&#xff1a;“30岁去应聘测试开发&#xff0c;拿不到七八十万的年薪确实有点丢人了&#xff0c;还被面试官diss混得太差了”&#xff0c;网友们看完都炸了。 来看看网友们都是怎么说的。 有网友说&#xff1a; 扯淡 有网友气到&#xff1a; 那拿…

接口自动化

为了实现真正意义上的接口自动化&#xff0c;一般使用yaml文件存储测试用例&#xff0c;代码调用里面的数据来发送请求 Controller RequestMapping("/send") public class Login {ResponseBodyRequestMapping("/login")public State login(String name,Str…

ES6-ES11基本全部语法

在进入es6语法之前&#xff0c;先走一波es5遍历迭代Api&#xff0c;&#xff0c;它们的作用&#xff0c;应用场景&#xff0c;参数&#xff0c;以及返回值分别是什么。&#xff08;forEach、map、some、every、filter&#xff09;我们统一设定一个初始数组&#xff1a;let arra…

Prophet 处理时间序列数据

Prophet 处理时间序列数据 flyfish 论文地址 https://peerj.com/preprints/3190/ 官网 https://facebook.github.io/prophet/ 源码地址 https://github.com/facebook/prophet hon import pandas as pd from prophet import Prophet df pd.read_csv(https://raw.githubuse…

2月23号作业

题目&#xff1a;题目一&#xff1a;通过操作Cortex-A7核&#xff0c;串口输入相应的命令&#xff0c;控制LED灯进行工作--->上传CSDN 1.例如在串口输入led1on,开饭led1灯点亮 2.例如在串口输入led1off,开饭led1灯熄灭 3.例如在串口输入led2on,开饭led2灯点亮 4.例如在串口输…

[HarekazeCTF2019]Easy Notes

知识点&#xff1a;session 反序列化&#xff0c;代码审计代码分析 flag.php 中有个 is_admin 函数的判断。 在 lib.php 中有 is_admin 函数&#xff0c;需要 session[admin] 为 true&#xff0c;或者通过文件读取的方式。 在 index.php 中的 include 并不能使用伪协议读取 …

JVM回顾与Java虚拟机的内存管理

目录 什么是JVM&#xff1f; 主流虚拟机 JVM与操作系统关系 JVM、JRE、JDK的关系 Java程序的执行过程 JVM翻译字节码有三种执行方式 Java虚拟机的内存管理 JVM整体架构图 JVM运行时内存 Java7和Java8内存结构的不同主要体现在方法区的实现 对于Java8&#xff0c;HotSp…

Hadoop MapReduce基本概念与详细流程

Hadoop MapReduce是Hadoop 中一个批量计算的框架&#xff0c;在整个mapreduce作业的过程中&#xff0c;包括从数据的输入&#xff0c;数据的处理&#xff0c;数据的数据输入这些部分&#xff0c;而其中数据的处理部分就要map&#xff0c;reduce&#xff0c;combiner等操作组成。…

刚接手的APP项目需要优化,需要从哪些方向入手?

对于每个Android 开发团队来说产品上线&#xff0c;是让人喜忧参半的一件事。**喜指的是&#xff1a;付出了大量的时间&#xff0c;产品终于上线了&#xff1b;而忧指的是&#xff1a;担心中间会不会出现一些性能相关的问题&#xff0c;比如卡顿、内存泄漏、崩溃……等&#xf…

干翻 nio ,王炸 io_uring 来了 !!(图解+史上最全)

大趋势&#xff1a;全链路异步化&#xff0c;性能提升10倍 随着业务的发展&#xff0c;微服务应用的流量越来越大&#xff0c;使用到的资源也越来越多。 在微服务架构下&#xff0c;大量的应用都是 SpringCloud 分布式架构&#xff0c;这种架构总体上是全链路同步模式。 全链…

java 抽象类 详解

目录 一、抽象类概述&#xff1a; 二、抽象方法 : 1.概述 : 2.应用 : 3.特点 : 三、抽象类特点 : 1.关于abstract关键字 : 2.抽象类不能被实例化&#xff0c;只能创建其子类对象 : 3.抽象类子类的两个选择 &#xff1a; 四、抽象类的成员 : 1.成员变量 : 2.成员方…

趣味三角——第12章——tanx

第12章节 tanx In his very numerous memoires, and especially in his great work, Introductio in analysin infinitorum (1748), Euler displayed the most wonderful skill in obtaining a rich harvest of results of great interest. . . . Hardly any other work …

业务单据堆积如山?如何提升会计做账效率?

某集团以“创建现代能源体系、提高人民生活品质”为使命&#xff0c;形成了贯通下游分销、中游贸易储运、上游生产的清洁能源产业链和涵盖健康、文化、旅游、置业的生命健康产品链。目前&#xff0c;某集团在全国21个省&#xff0c;为超过2681万个家庭用户、21万家企业提供能源…

Android:同步屏障的简单理解和使用

同步屏障的简单理解和使用1、背景2、何为同步屏障&#xff1f;2.1、 发送屏障消息——postSyncBarrier2.2、发送异步消息2.3、处理消息2.4、移除屏障消息——removeSyncBarrier2、系统什么时候添加同步屏障&#xff1f;参考1、背景 这里我们假设一个场景&#xff1a;我们向主线…

网狐服务端C++引入http功能剖析

旗舰版本的网狐服务端及以前的版本都是没有http解析功能的&#xff0c;导致就是web后台改了配置不能及时通知到游戏里面去&#xff0c;以至于很多小公司拿这种框架来开发的变通的方案就是用定时器不定时去刷数据库&#xff0c;导致多少个功能就有多少个定时去刷新&#xff0c;代…