哈希应用全解

目录

一.   位图

1.1   概念

1.2   bitset使用

1.3   实现

1.4   位图的应用

 二.   布隆过滤器

2.1   布隆过滤器的提出

2.2   概念

 2.3   布隆过滤器基本结构定义

2.4   插入

2.5   查找

2.6   删除

2.7   布隆过滤器优点

2.8   布隆过滤器缺点

 三.   哈希切割

四.   面试题


一.   位图

1.1   概念

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

例如:给你40亿个不重复的无符号整数,没有排过序,给你一个无符号整数,如何快速判断这个树在不在这40亿个数之中?

第一眼看是不是人都傻了,40亿个整数,相当于16G的内存,如果我们将他放到一个数组中,这个数组的长度就爆炸了,而且内存也开不了这么大的空间。那怎么办呢?

我们放在数组中是以一个整型的形式存储的,那我们是不是可以缩小一下用一个bite位来看呢,是不是这个内存占用就减小了8倍,是不是大大节约了空间。

这就是我们位图的基本思想,那好我们就用每一个bite位的状态(0或者1)来显示在不在。

1.2   bitset使用

根据上面的分析,可以看出我们位图有着三个基本的实现。

  1. 将一个bite位的状态变为1。
  2. 将一个bite位的状态变为0。
  3. 检查这个数所在的位置状态是不是1,为1就返回true。
set(size_t pos);//将pos数所映射的bit位标记为1reset(size_t pos);//将pos数所映射的bit标记回0test(size_t pos);//检测pos数所映射的bit为是否为1,为1则返回true

1.3   实现

我们这里用vector<int>来实现位图这个结构,为什么要用int呢?因为我们是用32位bite位为一个单位,刚好是一个整形,所以就用int,也可以用char。

那么如果有N个数,首先对vector进行开空间,我们这里要开N/32+1个整型空间,并把每个位置的初始值给0,为什么要多开一个呢?因为不能保证N一定是32的倍数,可能会多余几个数,所以多开32个bite位,即+1。而且即使浪费也只多浪费一个整型。

  1. set函数:将某个数字对应的位置的状态变为1。具体操作是:首先看这个数是位于第几个空间(一个空间32个bite位)-》x/32,再看这个数在这个空间的那个位置-》x%32,那么让这个位置的状态变为1,可以用到或(|)运算
  2. reset函数:将某个数字对应的位置的状态变为0。具体操作是:还是先找到位于哪个空间的哪个位置,然后用与(&)运算
  3. test函数:检测某个数的状态是否为1。具体操作是:找到这个数的位置,然后用这个位置的状态与运算1
//把x映射的位置标记成1
void set(size_t x)
{assert(x <= N);size_t i = x / 32;size_t j = x % 32;_bits[i] |= (1 << j);//此处左移是向高位移的意思,不是普通意义上想左移//此处是以一个整型为单位
}//把x映射的位置标记成0
void reset(size_t x)
{assert(x <= N);size_t i = x / 32;size_t j = x % 32;_bits[i] &= ~(1 << j);
}bool test(size_t x)
{assert(x <= N);size_t i = x / 32;size_t j = x % 32;return _bits[i] & (1 << j);
}

 需要注意的是:我们这里不论是&还是|,都是对于同一bite位上的数来运算。因此要用到移位操作符(<<),这里左移指的是向高位移动,并不是书面上的向左移。

对于set来说:

对于reset来说:

对于test来说:

1.4   位图的应用

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

 二.   布隆过滤器

2.1   布隆过滤器的提出

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

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

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

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

2.2   概念

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

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

 2.3   布隆过滤器基本结构定义

布隆过滤器用到了位图的三个函数。

struct HashFuncBKDR
{// BKDRsize_t operator()(const string& s){size_t hash = 0;for (auto ch : s){hash *= 131;hash += ch;}return hash;}
};struct HashFuncAP
{// APsize_t operator()(const string& s){size_t hash = 0;for (size_t 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 HashFuncDJB
{// DJBsize_t operator()(const string& s){size_t hash = 5381;for (auto ch : s){hash = hash * 33 ^ ch;}return hash;}
};template<size_t N,class K=string,class Hash1=HashFuncBKDR,class Hash2=HashFuncAP,class Hash3=HashFuncDJB>
class BloomFilter
{
private:static const size_t M = 5 * N;std::bitset<M>* _bs=new std::bitset<M>;
};

2.4   插入

void set(const K& key)
{size_t hash1 = Hash1()(key) % M;//匿名对象调用size_t hash2 = Hash2()(key) % M;size_t hash3 = Hash3()(key) % M;_bs->set(hash1);_bs->set(hash2);_bs->set(hash3);
}

用哈希函数算出对应映射的位置,将位置的状态变为1即可。

2.5   查找

bool Test(const K& key)
{size_t hash1= Hash1()(key) % M;if (_bs->test(hash1) == false){return false;}size_t hash2 = Hash2()(key) % M;if (_bs->test(hash2) == false){return false;}size_t hash3 = Hash3()(key) % M;if (_bs->test(hash3) == false){return false;}return true;
}

分别计算每个哈希值对应的比特位置存储的是否为0,只要有一个为0,代表该元素一定不在哈希表中,否则可能在哈希表中。

注意:布隆过滤器如果说某个元素不存在时,该元素一定不存在,如果该元素存在时,该元素可 能存在,因为有些哈希函数存在一定的误判。

2.6   删除

布隆过滤器是不能支持删除的,因为不同的元素可能映射相同的位置,删除了某个元素后,可能改变了其他元素在对应位置的状态。

但是有一种删除方法是:将布隆过滤器中的每个比特位扩展成一个小的计数器,插入元素时给k个计数器(k分哈希函数计算处的哈希地址)+1,在删除元素时,给k个计数器-1,这样通过多占几倍的存储空间代价来增加删除操作。

2.7   布隆过滤器优点

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

2.8   布隆过滤器缺点

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

 三.   哈希切割

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

此处的话,可以用map<string,int>,属于kv模型,不能用布隆过滤器(布隆过滤器本质就是位图,是解决类型不是整型的时候的情况),我们可以用到哈希切割的思想。

我们可以依次取ip,让每个ip%100,这样就将ip分到100个不同的区间里面,那么相同的ip就在相同的区间了。

还有一个问题,可能出现某个ip太多,这样冲突很多,那么map就会抛异常,这时就需要更换哈希函数,进行二次切分处理。

而找topk的话,就可以建堆来处理。

四.   面试题

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

这个题还是用位图来解决。需要注意的是一种情况:如果我们位图需要1个G的内存,但是只有512MB怎么办呢?

我们可以分成两个位图来处理:第一个位图处理0~2^31-1的数据直接映射,第二个位图处理2^31~2^32-1的数据减去2^31之后再映射。

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

我们可以分别映射到两个位图中去,那么在两个位图相同位置状态都为1的元素就是交集。

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

我们还是可以用两个位图来解决,那么两个位图某个相同位置的状态组合起来就只有四种(00,01,10,11),我们用00代表0次,01代表1次,10代表两次,11代表3次及以上。那么只需看哪些是00,01,10的就可以看出了。

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

这里的近似算法就是我们的布隆过滤器,我们主要来讲讲精确算法。 

我们可以对两个文件的query进行哈希切割(query%1000),分别是两个文件中的query进入两组1000个的文件组中,第一个文件的放到A中,第二个文件放到B中。A和B的query继续分别放到连个该set中,找交集即可。

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

每个位置给多个bite的引用计数做标记,比如一个位置给8bite位做标记,但是这样空间消耗就高了。


总结

好了,到这里今天的知识就讲完了,大家有错误一点要在评论指出,我怕我一人搁这瞎bb,没人告诉我错误就寄了。

祝大家越来越好,不用关注我(疯狂暗示)

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB求和函数

语法 S sum(A) S sum(A,“all”) S sum(A,dim) S sum(A,vecdim) S sum(,outtype) S sum(,nanflag) 说明 示例 S sum(A) 返回沿大小大于 1 的第一个数组维度计算的元素之和。 如果 A 是向量&#xff0c;则 sum(A) 返回元素之和。 如果 A 是矩阵&#xff0c;则 sum(A) 将…

const成员函数 以及 取地址及const取地址操作符重载

目录 const成员函数 结论&#xff1a; 取地址及const取地址操作符重载 const成员函数 将const 修饰的 “ 成员函数 ” 称之为 const成员函数 &#xff0c; const 修饰类成员函数&#xff0c;实际修饰该成员函数的&#xff08;*this&#xff09; &#xff0c;表明在该成员函数…

【MySQL】查询(进阶)

文章目录 前言1、新增2、聚合查询2.1聚合函数2.1.1count2.1.2sum2.1.3avg2.1.4max和min 2.2、GROUP BY子句2.3HAVING 3、联合查询/多表查询3.1内连接和外连接3.2自连接3.3子查询3.4合并查询 前言 在前面的内容中我们已经把查询的基本操作介绍的差不多了&#xff0c;接下来我们…

OpenHarmony鸿蒙南向开发案例:【智能猫眼(基于3518开发板)】

样例简介 本Demo是基于Hi3518开发板&#xff0c;使用开源OpenHarmony开发的RTSP协议流媒体应用。达到将Hi3518开发板中摄像头获取的数据通过RTSP协议传输到手机并显示 。 rtsp实现可参考文档&#xff1a;openharmony_1.0.1实现RTSPServer 运行效果 样例原理 如上图所示&…

Linux应用开发(8):Linux进程间通信(IPC):管道

Linux应用开发&#xff08;7&#xff09;&#xff1a;Linux进程间通信&#xff08;IPC&#xff09;&#xff1a;POSIX消息队列https://blog.csdn.net/tecsai/article/details/137879465 1. 简述 我们在前面已经介绍了进程间通信&#xff08;IPC&#xff09;常用的“消息队列”…

Latex篇之数学公式

数学公式 背景 科研小白在Latex中踩了不少坑&#xff0c;在此记录一下。 准备资料 以下两份文档可以说贯穿写作始终&#xff0c;务必下载&#xff08;快速过一遍即可&#xff0c;知道怎么用&#xff09; 一份&#xff08;不太&#xff09;简短的 LATEX 2ε 介绍&#xff1…

编写函数fun,它的功能是:根据以下公式求P的值,结果由函数值带回。m与n为两个正整数且要求m>n

本文收录于专栏:算法之翼 https://blog.csdn.net/weixin_52908342/category_10943144.html 订阅后本专栏全部文章可见。 本文含有题目的题干、解题思路、解题思路、解题代码、代码解析。本文分别包含C语言、C++、Java、Python四种语言的解法完整代码和详细的解析。 题干 编写…

Axure如何实现限制选择项数量的交互

大家经常会看到这样的功能设计&#xff1a;可以多选&#xff0c;但是限制多选。比如某招聘网站城市的选择只能选择5个。再选择第6个的时候会提示最多只能选择5项。 这个效果是我们经常会遇到的&#xff0c;在工作中也经常会遇到需要制作这样的效果。今天我们一起来看看&#xf…

光盘完成-qt-动画

QPropertyAnimation 是 Qt 中用于属性动画的类&#xff0c;它允许你动画化任何 QObject 的属性。当你使用 QPropertyAnimation&#xff0c;你应该注意以下几点&#xff1a; 1. **对象和属性的类型**&#xff1a; - QPropertyAnimation 仅支持继承自 QObject 的对象&#xf…

日期类的实现

目录 Date.h Test.cpp 测试代码Test.cpp 日期类的实现 代码分享 Date.h #pragma once #include<iostream> using namespace std; #include<assert.h>class Date {//友元函数声明friend ostream& operator<<(ostream& out, Date& d);friend…

书生·浦语大模型全链路开源体系-第5课

书生浦语大模型全链路开源体系-第5课 书生浦语大模型全链路开源体系-第5课相关资源LMDeploy基础配置LMDeploy运行环境下载internlm2-chat-1_8b模型使用Transformer来直接运行InternLM2-Chat-1.8B模型使用LMDeploy以命令行方式与InternLM2-Chat-1.8B模型对话设置KV Cache最大占用…

2024 Guitar Pro如何加音乐符号及功能介绍

一、新版本特性概览 Guitar Pro v8.1.1 Build 17在保留了前版本强大功能的基础上&#xff0c;进一步优化了用户体验和功能性能。新版本主要更新包括以下几个方面&#xff1a; 界面优化&#xff1a;新版界面更加简洁美观&#xff0c;操作更加便捷&#xff0c;即使是初学者也能快…