哈希思想的应用

news2024/11/27 12:41:48

目录

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的次数,之后再利用栈来记录次数最多的即可。

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

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

相关文章

Alfred v5.1.4(mac快速启动)

Mac效率办公软件哪个好&#xff1f;Alfred是一款Mac电脑上的快速启动和工作流自动化工具&#xff0c;它可以帮助用户快速访问文件、应用程序、web搜索和系统工具&#xff0c;提高工作效率。以下是Alfred的特点&#xff1a; 快速启动&#xff1a;用户可以通过Alfred快速启动应用…

【Linux】bash 终端指令

进程 $ ps aux | grep pwd work 63317 0.0 0.0 51192 612 pts/9 S 14:22 0:00 grep /home/work/search/1000000.dyenv-user-diaoyan-baiseCliPlus-baisePlus-195522.diaoyan.yq/ala-ac/output_root端口 查看本机端口开放情况 $ netstat -tln | grep 3200 tcp…

Arduino驱动温湿度气压光照传感器模块

目录 一、简介二、原理图三、使用方法四、实验现象 一、简介 点击图片购买 HTU21D特性&#xff1a;HTU21D基于法国Humirel公司高性能的湿度感应元件制成&#xff0c;传感器输出标准IIC格式。同时具有很高的温度精度和湿度精度。HTU21专为低功耗小体积应用设计&#xff0c;具有很…

3. 迷宫问题

题目 迷宫有一个入口&#xff0c;一个出口。一个人从入口走进迷宫&#xff0c;目标是找到出口。阴影部分和迷宫的外框为墙&#xff0c;每一步走一格&#xff0c;每格有四个可走的方向&#xff0c;探索顺序为地图方向&#xff1a;南&#xff08;下&#xff09;、东&#xff08;右…

【Spring整合MyBatis】Spring整合MyBatis的具体方法

在前面写的博客中&#xff0c;介绍了MyBatis通过配置方式和通过注解方式写的方法&#xff1a; 【Spring集成MyBatis】MyBatis诞生及代码快速入门&#xff08;非注解开发&#xff09;【Spring集成MyBatis】MyBatis的Dao层实现&#xff08;基于配置&#xff0c;非注解开发&#…

【libGDX】立方体手动旋转

1 前言 本文主要介绍使用 libGDX 绘制立方体&#xff0c;并实现手动触摸事件控制立方体旋转。 为方便控制触摸旋转&#xff0c;并提高渲染性能&#xff0c;我们通过改变相机的位置和姿态实现立方体旋转效果。 读者如果对 libGDX 不太熟悉&#xff0c;请回顾以下内容。 使用Me…

Re55:读论文 Entities as Experts: Sparse Memory Access with Entity Supervision

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称&#xff1a;Entities as Experts: Sparse Memory Access with Entity Supervision 模型名称&#xff1a;Entities as Experts (EaE) ArXiv网址&#xff1a;https://arxiv.org/abs/2004.07202 本文…

轻松实现文件按数量平均分类,高效整理并自动新建文件夹保存“

你是否曾经因为文件数量过多&#xff0c;整理起来繁琐而感到烦恼&#xff1f;是否曾经为了新建文件夹而手动一个一个进行创建&#xff0c;费时又费力&#xff1f;现在&#xff0c;我们的智能文件管理工具将为你解决这些问题&#xff01; 首先第一步&#xff0c;我们要进入文件…

超详细csapp-linklab之第一阶段“输出学号”实验报告

该实验的主题是“链接”。 准备工具 虚拟机&#xff0c;Ubuntu32位&#xff0c;hexedit&#xff0c;main.o&#xff0c;phase1.o&#xff0c;该实验的C代码框架如下 // main.c void (*phase)(); /*初始化为0*/int main( int argc, const char* argv[] ) {if ( phase )(*ph…

小程序项目:springboot+vue基本微信小程序的宠物领养系统

项目介绍 当今科技发展迅速&#xff0c;交通环境也变得越来越复杂。人们的出行方式变得多元化&#xff0c;这给视障人士带来了一定的困扰。而导盲犬可以帮助视障人士外出行走&#xff0c;提高他们的生活质量。在我国&#xff0c;导盲犬的数量远远少于视障人士的数量。由于导盲…

FreeRTOS深入教程(中断管理)

文章目录 前言一、为什么要为中断设计一套API二、两套函数区别对比三、两类中断四、FreeRTOS中SYSTICK和PendSV中断的作用总结 前言 本篇文章来分析FreeRTOS中的中断&#xff0c;中断在FreeRTOS中也是非常重要的&#xff0c;那么这篇文章将带大家来学习一下FreeRTOS中的中断处…

文件搜索工具HoudahSpot mac中文版特点

HoudahSpot mac是一款文件搜索工具&#xff0c;它可以帮助用户快速准确地找到文件和文件夹&#xff0c;支持高级搜索和过滤&#xff0c;同时提供了多种视图和操作选项&#xff0c;方便用户进行文件管理和整理。 HoudahSpot mac软件特点 高级搜索和过滤功能&#xff1a;软件支持…

[pyqt5]pyqt5设置窗口背景图片后上面所有图片都会变成和背景图片一样

pyqt5的控件所有都是集成widget&#xff0c;窗体设置背景图片后控件背景也会跟着改变&#xff0c;此时有2个办法。第一个办法显然我们可以换成其他方式设置窗口背景图片&#xff0c;而不是使用styleSheet样式表&#xff0c;网上有很多其他方法。还有个办法就是仍然用styleSheet…

vsVode C++开发远程虚拟机工程配置

在使用VS Code进行C/C的开发过程中&#xff0c;有三个至关重要的配置文件&#xff0c;分别是 tasks.json, launch.json 和 c_cpp_properties.json 1. tasks.json tasks.json 是在 vscode 中辅助程序编译的模块&#xff0c;可以代你执行类似于在命令行输入 “gcc hello.c -o h…

在mysql存储过程中间部分,使用游标遍历动态结果集(游标动态传参使用)

mysql游标动态传参实现&#xff08;动态游标&#xff09; 1.问题2.需求描述3.实现3.1.使用3.2.代码&#xff08;直接看这都可以&#xff09; 1.问题 众所周知&#xff0c;mysql存储过程功能是没有oracle的包功能强大的&#xff0c;但是在去O的趋势下&#xff0c;mysql存储过程的…

17. Python 数据库操作之MySQL和SQLite实例

目录 1. 简介2. 使用PyMySQL2. 使用SQLite 1. 简介 数据库种类繁多&#xff0c;每种数据库的对外接口实现各不相同&#xff0c;为了方便对数据库进行统一的操作&#xff0c;大部分编程语言都提供了标准化的数据库接口&#xff0c;用户不需要了解每种数据的接口实现细节&#x…

2018年5月23日 Go生态洞察:更新Go行为准则

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

智能优化算法应用:基于蚁狮算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蚁狮算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蚁狮算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蚁狮算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

ElasticSearch学习笔记(狂神说)

ElasticSearch学习笔记&#xff08;狂神说&#xff09; 视频地址&#xff1a;https://www.bilibili.com/video/BV17a4y1x7zq 在学习ElasticSearch之前&#xff0c;先简单了解一下Lucene&#xff1a; Doug Cutting开发是apache软件基金会 jakarta项目组的一个子项目是一个开放…

乘波前行的问题

1.问题&#xff1a; 考虑两个信号叠加在一起&#xff0c;比如&#xff0c;一个是工频信号50Hz&#xff0c;一个是叠加的高频信号比如有3KHz&#xff0c;简单起见&#xff0c;两个信号都是幅值固定的标准的正弦波&#xff0c;现在我们期望得到那个高频信号&#xff0c;相对工频…