哈希思想的应用

目录

1.位图

位图的实现

题目变形一

题目变形二

题目变形三

总结:

2.布隆过滤器

概念

布隆过滤器的实现

3.哈希切割的思想


1.位图

     哈希表和位图是数据结构中常用的两种技术。哈希表是一种数据结构,通过哈希函数把数据和位置进行映射,来实现快速的寻找、插入和删除操作。哈希表适用于海量数据处理,索引,数据压缩等方面有广泛应用123. 位图主要用于海量数据处理,索引,数据压缩等方面有广泛应用。位图的应用场景包括:

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

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

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

如下题目:

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在
这40亿个数中。【腾讯】
位图解决
那么如何实现呢:
数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一
个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0
代表不存在。
  
    首先40亿个整数大概需要4G*4的空间,16个g的空间,我们是无法开出这么大的空间,其次我们用数组访问,因此还是连续l6个g的空间,很明显,我们无法实现,那么如何来解决这个问题呢?
      首先我们没必要把这么多数据存下来,我们只需要判断它在不在,而标记一个值在不在,最小的单位就是一个比特位,那么我们一个值映射一个比特位,就可以来表示这么多数据的存在情况。
此时我们只需要0.5G的空间即可,即42亿个比特位,此时0.5G就可以开出来了。

位图的实现

0.5G我们开不出bit类型的,我们只能开出整形或字符类型的。因此这里直接用vector来映射,因此我们需要计算出映射的位置。

如判断x是否存在,则我们需要计算x在第几个整形的第几个bit位上。

template<size_t N>class bitset
{
public:
	bitset()
	{
		_bit.resize(N/32);
	}
	void set(size_t x)
	{
		size_t i = x / 32;//第几个整形
		size_t j = x % 32;//第几个位
		//找到该位置并置1 ,利用位运算计算
		//注意左移是向高位移,右移是向低位移
		_bit[i] |= (1 << j);//这里1左移再或上原数据,重新赋值后,该比特位就修改成1
	}
	void reset(size_t x)
	{
		//与set相反,这里是将原来的x有存在变为不存在,不存在变为存在

		size_t i = x / 32;//第几个整形
		size_t j = x % 32;//第几个位
		//找到该位置
		//1变0   0变1
		_bit[i] &= ~(1 << j);
	}

	//检测是否中存在,即该位置是1还是0
	bool test(size_t x)
	{
		size_t i = x / 32;
		size_t j = x % 32;
		return _bit[i] & (1 << j);
	}
private:
	//数据个数足够大,用16进制表示
	std::vector<int> _bit;
	size_t size;
};

题目变形一

给100亿个整数,找出其中出现一次的数。
/用两个数组表示两个bit位   
//用两位bit位映射一个数三种状态,存在,不存在,个数
//00 不存在  01存在   10两个以上的个数
template<size_t N>class twobitset
{
public:
	void set(const size_t x)
	{
		if (bit1.test(x) == false && bit2.test(x) == false)//0 0 -> 0 1
		{
			bit2.set(x);
		}
		else if (bit1.test(x) == false && bit2.test(x) == true) //0 1 -> 1 0 
		{
			bit1.set(x);
			bit2.reset(x);
		}
	}
private:
	bitset<N> bit1;
	bitset<N> bit2;
};

题目变形二

给两个文件分别有100亿个整形数据,只有1G空间,找i出他们的交集。
解决方法:
各自映射到一个位图,两个位图如果都是存在,那么就是两者的交集的元素。

题目变形三

给定100亿个整数,1G内存,设计找到不查过2次的数据。
解决方案,用两个比特位表示四种状态:
00 不存在, 01存在,10有两个,11有三个以上。
template<size_t N>class twobitset
{
public:
	void set(const size_t x)
	{
		if (bit1.test(x) == false && bit2.test(x) == false)//0 0 -> 0 1
		{
			bit2.set(x);
		}
		else if (bit1.test(x) == false && bit2.test(x) == true) //0 1 -> 1 0 
		{
			bit1.set(x);
			bit2.reset(x);
		}
		else if (bit1.test(x) == true && bit2.test(x) == false;)// 10 ->11
		{
			bit1.set(x);
			bit2.set(x);
		}
	}
private:
	bitset<N> bit1;
	bitset<N> bit2;
};

总结:

对于搜索:

1.暴力查找,数据量太大,效率太低。

2.排序+二分查找 ,极大的提升了效率。但还是存在不足:要排序。数组不方便增删。

3.引入搜索树,AVL树,红黑树。查找效率已经很可观了,但空间消耗较高。

4.哈希  ,与搜索树效率差不多,但对于大量搜索的整型数据,通过映射bit的思想实现更加高效,且节省空间。(但只能处理整形)

对于其他类型的,引出了布隆过滤器:

2.布隆过滤器

概念

布隆过滤器是一种概率型数据结构,用于判断一个元素是否在一个集合中。它可以节省空间和时间,但有一定的误判率:

1. 布隆过滤器的核心是一个位数组,即一个只包含0和1的数组,以及一组哈希函数,即一组可以将任意元素映射到位数组的索引的函数。

2. 当要添加一个元素时,先用哈希函数计算出它在位数组中的多个索引,然后将这些索引对应的值都设为1. 当要检查一个元素是否存在时,也先用哈希函数计算出它在位数组中的多个索引,然后检查这些索引对应的值是否都为1. 如果都为1,说明元素可能存在,如果有一个为0,说明元素一定不存在。

上述说了位图,我们知道位图可以来查找大量整形数据,但是对于其他类型,如字符型,就无法去查找,此时我们就需要有一种方法将他搞成整形。

直接用ascll码肯定不行,再通过哈希字符串算法转化一下,但是仍会有较大的冲突,还是有大概率的值是一样的,为了减少这些冲突,我们让一个字符串对应三个或者更多的哈希字符串算法转化后的整形,只有当这些整型值都存在的时候才存在,大大减少了重复带来的问题。各种字符串Hash函数 - clq - 博客园 (cnblogs.com)

但是还是存在问题:即使我们让一个字符串对应了三个转化后的数,但还是存在别的字符串也会对应这三个转化后的数(将不存在的判断为存在的),我们只能尽可能的减少这种情况,因此是否存在我们还是有不确定因素,但不存在我们一定能够能确定。

一个字符串对应的三个整数的对应比特位设置为1.

总的来说,存在误判率,但概率已经不是很大了。

那么如何选择n(插入元素个数)和k(映射的个数)的值呢?

有人给出了公式计算这里的m是布隆过滤器的长度。我们先以k=3先来实现。

布隆过滤器的实现

#pragma once
#include"bitset.h"
//这里我们就选用3个映射值来对应一个字符串,每一个映射值我们选取一种hash字符串算法
#include<string.h>
struct BKDR
{
	size_t operator()(const std::string& key)
	{
		// BKDR
		size_t hash = 0;
		for (auto e : key)
		{
			hash *= 31;
			hash += e;
		}

		return hash;
	}
};
struct AP
{
	size_t operator()(const std::string& str)
	{
		 size_t hash = 0;
		int i = 0;
		char ch = str[i];
		for (auto ch: str)
		{
		
			if ((i & 1) == 0)
			{
				hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
			}
			i++;
		}
		return hash;
	}
};
struct SDB
{
	size_t operator()(const std::string& str)
	{
	     size_t hash = 0;
		for(auto ch:str)
		{
			hash = 65599 * hash + ch;
		}
		return hash;
	}
};
template<size_t N,class K=std::string,
	class HashFunc1= BKDR,
	class HashFunc2 = AP,
	class HashFunc3 = SDB>
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;

		_bit.set(hash1);
		_bit.set(hash2);
		_bit.set(hash3);
	}
	bool test(const K& key)
	{
		size_t hash1 = HashFunc1()(key) % N;
		size_t hash2 = HashFunc2()(key) % N;
		size_t hash3 = HashFunc3()(key) % N;
		//只有当三个映射值都存在是才能表示存在
		if (_bit.test(hash1) == true&& _bit.test(hash2) == true&& _bit.test(hash3) == true)
		{
			return true;//存在误判
		}
		return false;
	}
	/*double wrongrate()
	{
		return  
	}*/

private:
	//用位图封装
	bitset<N> _bit;
};

 事实上,空间开得越多,选用的映射值越多,都会之误判律极大地降低。

   对于布隆过滤器,一般是不支持删除的,我们在删除一个值这会影响以他的字符串成员存在变成不存在,如若像删除,就必须要引用计数,增加计数位(多个比特位),即对应的哈希值在每一次被set之后,对应的计数位++,判断是否存在时,同时添加计数位是否为零,其次删除后,就减减计数位的值,不过还是消耗了空间。

3.哈希切割的思想

​​​​​​​     哈希切割是一种将大文件分割成若干个小文件的方法,以便于处理海量数据。该方法使用哈希函数将相同的数据分配到同一个文件中。这种方法可以用于处理日志文件等大小超过100GB的文件

例题:

1. 给两个文件,分别有 100 亿个 query ,我们只有 1G 内存,如何找到两个文件交集?分别给出
精确算法和近似算法
解题思路:先将两个大文件各分割成新一个个小文件,之后两边的小文件分别比较,如何比较呢?
我们需要将100亿个query进行哈希切割,即把每一个query转化为整形在对其size取模,算出的值就是他对应的小文件。
变形2:
2.若是找出它出现次数前topk个query?如何查找
      还是哈希切割思想,进行哈希切割,我们将字符串(query)利用哈希算法转化为整型,此时的值对应他的位置,而这里的位置就是对应的小文件,
小文件我们就可以直接用map或者unoderedmap来映射query的次数,之后再利用栈来记录次数最多的即可。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

公司人事管理系统

1.问题描述 一个小公司包含四类人员&#xff1a;经理&#xff0c;技术人员&#xff0c;销售人员和销售经理&#xff0c;各类人员的工资计算方法如下&#xff1a;经理&#xff1a;固定月薪&#xff08;8000&#xff09;&#xff1b;技术人员&#xff1a;月薪按技术等级&#xf…

【LeetCode】挑战100天 Day15(热题+面试经典150题)

【LeetCode】挑战100天 Day15&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-172.1 题目2.2 题解 三、面试经典 150 题-173.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…

AI视频生成工具——Runway gen2 全功能超详细使用教程(2)

昨天给大家分享了Runway Gen1的使用教程&#xff0c;一篇文章就能让你轻松掌握使用文字和图像从现有视频生成新的视频技能&#xff0c;还没有看过的同学们可以回看过往文章。 Runway视频生成功能有3大核心成品 Gen1&#xff1a;视频转视频工具Gen2&#xff1a;视频生成编辑工…

阅读笔记——《Removing RLHF Protections in GPT-4 via Fine-Tuning》

【参考文献】Zhan Q, Fang R, Bindu R, et al. Removing RLHF Protections in GPT-4 via Fine-Tuning[J]. arXiv preprint arXiv:2311.05553, 2023.【注】本文仅为作者个人学习笔记&#xff0c;如有冒犯&#xff0c;请联系作者删除。 目录 摘要 一、介绍 二、背景 三、方法…

集线器-交换机-路由器

1.集线器(Hub) 集线器就是将网线集中到一起的机器&#xff0c;也就是多台主机和设备的连接器。集线器的主要功能是对接收到的信号进行同步整形放大&#xff0c;以扩大网络的传输距离&#xff0c;是中继器的一种形式&#xff0c;区别在于集线器能够提供多端口服务&#xff0c;也…

Rust UI开发(三):iced如何打开图片(对话框)并在窗口显示图片?

注&#xff1a;此文适合于对rust有一些了解的朋友 iced是一个跨平台的GUI库&#xff0c;用于为rust语言程序构建UI界面。 这是一个系列博文&#xff0c;本文是第三篇&#xff0c;前两篇的链接&#xff1a; 1、Rust UI开发&#xff08;一&#xff09;&#xff1a;使用iced构建…

2023年09月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 运行下面程序后,角色的x坐标值是?( ) A:100 B:90 C:110 D:120 答案:C 利用变量值作为条件,控制循环的次数。变量从0~10的过程中每次角色的x坐标都增加了10,当变量值为1…

人力资源管理后台 === 左树右表

1.角色管理-编辑角色-进入行内编辑 获取数据之后针对每个数据定义标识-使用$set-代码位置(src/views/role/index.vue) // 针对每一行数据添加一个编辑标记this.list.forEach(item > {// item.isEdit false // 添加一个属性 初始值为false// 数据响应式的问题 数据变化 视图…

牛客 算法 HJ103 Redraiment的走法 golang语言实现

题目 HJ103 Redraiment的走法 实现 package mainimport ("bufio""fmt""os""strconv""strings" )func main() {scanner : bufio.NewScanner(os.Stdin)nums : make([]int, 0)nums_len:0dp:make([]int, 0)for scanner.Scan()…

汇编实验2-2 查找匹配字符串笔记

一、数据段 1.字符串结尾&#xff1a;13,10&#xff0c;$ 2.设置格式控制字符串(这样就不用再写clrf函数了) 3.设置存关键字和句子的地址标签&#xff0c;以关键字为例 二、代码段 1.输入字符串 2.字符串比较 2.1 每次的比较长度&#xff0c;KLEN->CL 2.2 设置目标串起始…

java学习part12多态

99-面向对象(进阶)-面向对象的特征三&#xff1a;多态性_哔哩哔哩_bilibili 1.多态&#xff08;仅限方法&#xff09; 父类引用指向子类对象。 调用重写的方法&#xff0c;就会执行子类重写的方法。 编译看引用表面类型&#xff0c;执行看实际变量类型。 2.父子同名属性是否…

游览器缓存讲解

浏览器缓存是指浏览器在本地存储已经请求过的资源的一种机制&#xff0c;以便在将来的请求中能够更快地获取这些资源&#xff0c;减少对服务器的请求&#xff0c;提高页面加载速度。浏览器缓存主要涉及到两个方面&#xff1a;缓存控制和缓存位置。 缓存控制 Expires 头&#…

力扣每日一题-统计和小于目标的下标对数目-2023.11.24

力扣每日一题&#xff1a;统计和小于目标的下标对数目 开篇 今天这道力扣打卡题写得我好狼狈&#xff0c;一开始思路有点问题&#xff0c;后面就是对自己的代码到处缝缝补补&#xff0c;最后蒙混过关。只能分享一下大佬的代码&#xff0c;然后我帮大家分享代码的思路。 题目链…

84基于matlab的数字图像处理

基于matlab的数字图像处理&#xff0c;数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 84matlab数字图像处理图像增强 (xiaohongshu.com)https://www.xiaohongshu.com/explore/656219d80000000032034dea

python+pytest接口自动化(1)-接口测试基础

一般我们所说的接口即API&#xff0c;那什么又是API呢&#xff0c;百度给的定义如下&#xff1a; API&#xff08;Application Programming Interface&#xff0c;应用程序接口&#xff09;是一些预先定义的接口&#xff08;如函数、HTTP接口&#xff09;&#xff0c;或指软件系…

【数据库基础】

目录&#xff1a; 前言什么是数据库主流数据库服务器&#xff0c;数据库&#xff0c;表关系MySQL架构SQL分类存储引擎 前言 剑指offer&#xff1a;一年又1天 什么是数据库 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件保存数据有以下几个缺点&#xff1a;…

数据结构之时间复杂度与空间复杂度

1.算法效率 1.1 如何衡量一个算法的好坏&#xff1f; 比方说我们非常熟悉的斐波拉契数列&#xff1a; long long Fib(int N) {if(N < 3)return 1;return Fib(N-1) Fib(N-2); } 递归实现方式非常简洁&#xff0c;但一定好吗&#xff1f;如何衡量其好与坏&#xff1f; 1…

ES6之class类

ES6提供了更接近传统语言的写法&#xff0c;引入了Class类这个概念&#xff0c;作为对象的模板。通过Class关键字&#xff0c;可以定义类&#xff0c;基本上&#xff0c;ES6的class可以看作只是一个语法糖&#xff0c;它的绝大部分功能&#xff0c;ES5都可以做到&#xff0c;新…

AndroidStudio2022.3.1 Patch3使用国内下载源加速

记录一下这个版本的as在使用国内下载源加速碰到的诸多问题。 一、gradle-8.0-bin.zip下载慢 编辑项目文件夹/gradle/wrapper/gradle-wrapper.properties&#xff0c;文件内容改为如下&#xff1a; #Fri Nov 24 18:50:06 CST 2023 distributionBaseGRADLE_USER_HOME distribu…

如何获得微软MVP徽章

要成为微软MVP&#xff0c;需要在特定领域成为专家&#xff0c;并积极参与社区&#xff0c;为其他人提供帮助和支持。以下是一些步骤可以帮助你成为MVP&#xff1a; 在特定领域成为专家&#xff1a;要成为MVP&#xff0c;需要在某个领域具有专业知识和经验。这可以通过阅读相关…