30 哈希的应用

位图

概念

题目

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

1.遍历,时间复杂度O(N)
2.二分查找,需要先排序,排序(N*logN),二分查找,logN。1个g大约存储10g字节,40亿个整数就需要160g字节,需要16个g的连续空间,内存中无法开出这么大的容量。
3.位图。判断一个数在不在的最小单位可以是位,将整数的范围全部做一个映射,有的值设置为1,没有就设置为0。这样,需要的空间就是42亿个位,0.5个g就可以存下

在这里插入图片描述
上面是3个字节的值,一个字节32位,可以表示的数的范围。计算一个值在第几个字节,在这个字节的第几个位。将一个数除以32就知道在第几个字节,取模就知道在第几个位,比如40,在第1个字节里,在第8位

位图概念

用每一位存放某种状态,适用于海量数据,数据无重复的场景,判断某个数据村部还存在的

实现

成员函数

可以用内置数组,这里直接用vector,成员类型是int

构造

为vector开辟需要的空间,每一位代表一个值,看需要多大的值,用非类型模板参数传入值。传入的是位,除以32再补上去的余数的一位,就是开辟多大整形的空间
在这里插入图片描述

set

将这个数据映射的值设为1。计算出数据所在的位,设置为1。i和j分别计算在第几个字节和第几位,让一个数的一位变为1,其他位不变化,可以或一个数,这个数这一位为1,其他位为0。可以将1左移j位就有了这个数

内存有大端和小端存储,左移都是往高位移动
在这里插入图片描述

reset

将这个数据清除,变为0。计算出i和j,让某一位变为0,可以与一个数,这个数这一位为0,其他都为1。1左移j位然后取反
在这里插入图片描述

test

查询一个数是否存在。1左移j位,与操作
在这里插入图片描述

#pragma once
#include <vector>//N是需要多少位
template <size_t N>
class bitset
{
public:bitset(){//多开一个防止不够_bit.resize(N / 32 + 1, 0);//_bit.resize( (N >> 5) + 1, 0)}void set(size_t x){int i = x / 32;int j = x % 32;_bit[i] = _bit[i] | (1 << j);}void reset(size_t x){int i = x / 32;int j = x % 32;_bit[i] = _bit[i] & ~(1 << j);}bool test(size_t x){int i = x / 32;int j = x % 32;return _bit[i] & (1 << j);}
public:std::vector<int> _bit;
};

测试

40亿的整数需要开辟的空间必须是无符号的整形大小,int是有符号的,所以用0xffffffff或-1
在这里插入图片描述

bitset<0xffffffff> bs;
bs.set(39256);
bs.set(43450);
bs.reset(40);cout << bs.test(24515) << endl;
cout << bs.test(32329) << endl;
cout << bs.test(39256) << endl;
cout << bs.test(2314) << endl;
cout << bs.test(43450) << endl;

在这里插入图片描述

应用

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

题目

1.给定100亿个整数,设计算法找到只出现一次的整数
位图用一个位标识两种状态,存在和不在,找到出现一次的数需要第三种状态,可以用两个位来保存一个数。也可以复用前面的位图,用一个结构,成员两个位图。set时,当两个位图表示的是00的时候,就设置为01,01就设置为10,10就不做任何改变。打印的时候打印出01状态的数字

template <size_t N>
class twobitset
{
public:void set(size_t x){//00 0次//01 1次//10 2次或以上int i = x / 32;int j = x % 32;if (_bs1.test(x) == false && _bs2.test(x) == false){_bs2.set(x);}else if (_bs1.test(x) == false && _bs2.test(x) == true){_bs1.set(x);_bs2.reset(x);}}void printOne(){for (size_t i = 0; i < N; i++){if (_bs1.test(i) == false && _bs2.test(i) == true){printf("%d ", i);}}printf("\r\n");}public:bitset<N> _bs1;bitset<N> _bs2;
};

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

和上面的方法一样,无论多少整数,还是申请42亿,两个位图里都有的就是交集

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

还是上面的类型,稍微修改,set函数10的时候变为11,11不变

template <size_t N>
class twobitset
{
public:void set(size_t x){//00 0次//01 1次//10 2次或以上int i = x / 32;int j = x % 32;if (_bs1.test(x) == false && _bs2.test(x) == false){_bs2.set(x);}else if (_bs1.test(x) == false && _bs2.test(x) == true){_bs1.set(x);_bs2.reset(x);}else if (_bs1.test(x) == true && _bs2.test(x) == false){_bs1.set(x);_bs2.set(x);}}void printOne(){for (size_t i = 0; i < N; i++){if (_bs1.test(i) == false && _bs2.test(i) == true){printf("一次%d ", i);}else if (_bs1.test(i) == true && _bs2.test(i) == false){printf("两次%d ", i);}}printf("\r\n");}public:bitset<N> _bs1;bitset<N> _bs2;
};

布隆过滤器

提出

每次看新闻时,会不断推荐新的内容,去掉已经看过的内容。问题来了,如何实现推送去重的,用服务器记录所有看过的记录,当推荐系统推荐新闻时从每个用户的历史记录里筛选,过滤掉已经存在的记录,怎么快速查找

目前搜索采用的各种方法
1.暴力查找,数据量太大了,效率就低
2.排序+二分查找,问题a:排序有代价 问题b:数组不方便增删
3.搜索树,avl树+红黑树
上面的数据结构对空间消耗的都很高,如果面对数据量很大的
5.[整形],在不在及其扩展问题,位图和变形,节省空间
6.[其他类型] 在不在,哈希和位图结合,布隆过滤器

概念

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

在这里插入图片描述

一个值映射一个比特位,冲突的概率很大,两个不同的字符串正好映射在一个比特位,这时判断的存在就是错误的。为了降低误判的概率,多映射几个比特位,映射的越多,消耗的空间就越多

插入

在这里插入图片描述在这里插入图片描述在这里插入图片描述上图中,当k3个时,100m数据误判率0.01已经很低了

在这里插入图片描述
按公式计算:
在这里插入图片描述
3个哈希函数,n和m的关系是4.3,约为4倍容量

查找

将一个元素用多个哈希函数映射到一个位图中,因此被映射到的位置比特位一定为1.所以可以按照以下方式进行查找:分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个零,代表该元素一定不在哈希表中,否则可能在哈希表中

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

删除

不能直接支持删除操作,因为在删除一个元素时,可能影响到其他元素
比如:删除上图的"tecent”元素,如果直接将该元素对应的二进制比特位置置为0,“baidu”元素也被删除了,因为这两个元素在多个哈希函数计算的比特位有重叠

一种支持删除的方法:将布隆罗氯气每个比特位扩展成一个小的计数器,插入元素时给k个计数器(k个哈希函数计算出的哈希地址)加一,删除元素时,给k个计数器减一,通过多占用几倍存储空间的代价来增加删除操作。如果引用计数最大为255时,映射的单位就必须扩展为8位

缺陷:
1.无法确认元素是否真正在布隆过滤器中
2.存在计数回绕

实现

#pragma once
#include <bitset>struct BKDRHash
{size_t operator()(const std::string& key){// BKDRsize_t hash = 0;for (auto e : key){hash *= 31;hash += e;}return hash;}
};struct APHash
{size_t operator()(const std::string& key){size_t hash = 0;for (size_t i = 0; i < key.size(); i++){char ch = key[i];if ((i & 1) == 0){hash ^= ((hash << 7) ^ ch ^ (hash >> 3));}else{hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));}}return hash;}
};struct DJBHash
{size_t operator()(const std::string& key){size_t hash = 5381;for (auto ch : key){hash += (hash << 5) + ch;}return hash;}
};template <size_t N, class K = std::string,class HashFunc1 = BKDRHash,class HashFunc2 = APHash,class HashFunc3 = DJBHash>
class BloomFilter
{
public:void set(const std::string& key){size_t hashi1 = HashFunc1()(key) % N;size_t hashi2 = HashFunc2()(key) % N;size_t hashi3 = HashFunc3()(key) % N;_bs.set(hashi1);_bs.set(hashi2);_bs.set(hashi3);}// 一般不支持删除,删除一个值可能会影响其他值// 非要支持删除,也是可以的,用多个位标记一个值,存引用计数// 但是这样话,空间消耗的就变大了void Reset(const K& key);bool test(const std::string& key){size_t hashi1 = HashFunc1()(key) % N;if (_bs.test(hashi1) == false)return false;size_t hashi2 = HashFunc2()(key) % N;if (_bs.test(hashi2) == false)return false;size_t hashi3 = HashFunc3()(key) % N;if (_bs.test(hashi3) == false)return false;return true;}private:std::bitset<N> _bs;
};

测试

#include <time.h>
#include <vector>
#include <iostream>
#include <string>
#include "bloom.h"int main()
{srand(time(0));const size_t N = 100000;BloomFilter<N * 4> bf;std::vector<std::string> v1;//std::string url = "https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html";std::string url = "猪八戒";for (size_t i = 0; i < N; ++i){v1.push_back(url + std::to_string(i));}for (auto& str : v1){bf.set(str);}// v2跟v1是相似字符串集(前缀一样),但是不一样std::vector<std::string> v2;for (size_t i = 0; i < N; ++i){std::string urlstr = url;urlstr += std::to_string(9999999 + i);v2.push_back(urlstr);}size_t n2 = 0;for (auto& str : v2){if (bf.test(str)) // 误判{++n2;}}std::cout << "相似字符串误判率:" << (double)n2 / (double)N << std::endl;// 不相似字符串集std::vector<std::string> v3;for (size_t i = 0; i < N; ++i){//string url = "zhihu.com";std::string url = "孙悟空";url += std::to_string(i + rand());v3.push_back(url);}size_t n3 = 0;for (auto& str : v3){if (bf.test(str)){++n3;}}std::cout << "不相似字符串误判率:" << (double)n3 / (double)N << std::endl;return 0;
}

在这里插入图片描述

优点

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

例如网页注册时,判断用户名存不存在。如果需要更进一步正确,可以将判断为存在的和数据库对比

缺陷

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

哈希切割

1. 给定两个文件,分别有100亿个query(字符串),只有1G内存,找到文件交集,精确算法和近似算法

近似算法就是上面的布隆过滤器
精确算法:
假设一个query有50个字节,100亿数据就需要500G,内存存不下,可以用哈希切分
读取每个query,计算i=Hash(query)%500,i是几,query就进入Ai小文件
在这里插入图片描述

A和B相同的字符串会进入相同编号的块里,只需要比较两个相同编号的块,就能找到交集
如果切分的某个文件大于10G,还是无法加载到内存里?
1.这个小文件大多数都是1个query
2.这个小文件,有很多不同的query

不管文件大小,直接读到内存插入set,如果是情况1,文件有很多重复,会去重
如果是情况2,插入后就会内存不足,抛异常,换一个哈希函数,二次划分,再找交集

2. 给一个超过100G大小的logfile,存ip地址,设计找出次数最多的ip地址

还是用哈希切分,相同的ip就进入了同一个小文件,然后用map统计次数。如果找topk,也可以用堆来解决

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

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

相关文章

2024年【焊工(初级)】考试及焊工(初级)报名考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 焊工&#xff08;初级&#xff09;考试是安全生产模拟考试一点通生成的&#xff0c;焊工&#xff08;初级&#xff09;证模拟考试题库是根据焊工&#xff08;初级&#xff09;最新版教材汇编出焊工&#xff08;初级&a…

C++ 史上首次超越 C,仅次于Python!【送源码】

TIOBE 公布了 2024 年 6 月的编程语言排行榜——C 史上首次超越 C&#xff0c;跃至榜二&#xff0c;仅次于 Python。 C 是一种广泛应用于嵌入式系统、游戏开发和金融交易软件等领域的语言&#xff0c;在本月成功超越了 C&#xff0c; 成为了 TIOBE 指数中新的第二名。 这是 C …

Gperftools交叉编译

Gperftools&#xff08;Google Performance Tools&#xff09;是由谷歌开发的一组性能分析工具。它包括了多个工 具&#xff0c;其中最为知名的是 tcmalloc&#xff08;Thread-Caching Malloc&#xff09;和 CPU Profiler。 相比与其他性能分析工具&#xff0c;gperftools有Pro…

四川省高等职业学校大数据技术专业建设暨专业质量监测研讨活动顺利开展

6月21日&#xff0c;省教育评估院在四川邮电职业技术学院组织开展全省高等职业学校大数据技术专业建设暨专业质量监测研讨活动。省教育评估院副院长赖长春&#xff0c;四川邮电职业技术学院党委副书记、校长冯远洪&#xff0c;四川邮电职业技术学院党委委员、副校长程德杰等出席…

鸿蒙开发设备管理:【@ohos.multimodalInput.inputConsumer (组合按键)】

组合按键 InputConsumer模块提供对按键事件的监听。 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。本模块接口均为系统接口&#xff0c;三方应用不支持调用。 导入模块 import inputConsumer …

36.基于多目标螳螂优化算法的微电网优化matlab

微♥关注“电击小子程高兴的MATLAB小屋”获取资源 基于螳螂优化算法的多目标优化算法 求解微电网多目标优化调度 比较不同目标函数寻优对调度结果的影响 第1种.将两个目标函数值归一化相加&#xff0c;取相加后最小的目标值的粒子&#xff0c;即寻找折衷解并画图 第2种寻找…

afterPropertiesSet方法的作用

在spring的bean的生命周期中&#xff0c;实例化->生成对象->属性填充后会进行afterPropertiesSet方法&#xff0c;这个方法可以用在一些特殊情况中&#xff0c;也就是某个对象的某个属性需要经过外界得到&#xff0c;比如说查询数据库等方式&#xff0c;这时候可以用到sp…

AI助力校园安全:EasyCVR视频智能技术在校园欺凌中的应用

一、背景分析 近年来&#xff0c;各地深入开展中小学生欺凌行为治理工作&#xff0c;但有的地方学生欺凌事件仍时有发生&#xff0c;严重损害学生身心健康&#xff0c;引发社会广泛关注。为此&#xff0c;教育部制定了《防范中小学生欺凌专项治理行动工作方案》进一步防范和遏…

在 Python 学习中,什么是变量,如何声明和使用变量?

一、什么是变量 变量是计算机编程中一个基本的概念&#xff0c;简单来说&#xff0c;变量是一个用于存储数据的命名位置。变量的值是可以变化的&#xff0c;因此被称为“变量”。在Python编程中&#xff0c;变量是用来保存数据的容器&#xff0c;可以将数据赋值给变量&#xf…

json文件 增删查改

默认收藏夹 qt操作json格式文件... 这个人的 写的很好 我的demo全是抄他的 抄了就能用 —————————— 下次有空把我的demo 传上来 在E盘的demo文件夹 json什么名字

Leetcode - 133双周赛

目录 一&#xff0c;3190. 使所有元素都可以被 3 整除的最少操作数 二&#xff0c;3191. 使二进制数组全部等于 1 的最少操作次数 I 三&#xff0c;3192. 使二进制数组全部等于 1 的最少操作次数 II 四&#xff0c;3193. 统计逆序对的数目 一&#xff0c;3190. 使所有元素都…

PyQt问题汇总(持续更新)

目录 1.抛出异常后QAppliaction自动闪退 2.Unbuntu共享文件夹自动挂载 1.抛出异常后QAppliaction自动闪退 开发阶段&#xff0c;PyQt5 QAppliaction会在遇到未捕获的异常时立即退出&#xff0c;它能够快速发现并报告错误&#xff0c;我在调用一些密码算法库的时候&#xff0…

Eureka三级缓存架构

Eureka Server缓存机制概述 Eureka是Netflix开源的服务发现框架&#xff0c;它具有高可用、可扩展、易于部署等优点&#xff0c;被广泛应用于微服务架构中。其中一个重要的组件就是Eureka Server&#xff0c;它负责维护服务注册表&#xff0c;以及向客户端提供服务注册信息。 …

FreeBSD虚拟化解决之道:高效、安全、灵活的虚拟解决方案全览

FreeBSD下的虚拟化技术 虚拟化软件可让一台计算机同时运行多个操作系统。这种用于个人电脑的系统软件通常涉及一个运行虚拟化软件的宿主机&#xff08;host&#xff09;操作系统&#xff0c;并支持任何数量的客户机&#xff08;guest&#xff09;操作系统。 FreeBSD下的虚拟解…

基于Java的地方废物回收机构管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java技术&#xff0c;MIS的总体思想&#xff0c;MySQL数据库 工具&#xff1a;Eclipse&#xff0c;…

【数据结构】详解二叉树之堆

失败只是暂时停止成功&#xff0c;假如我不能&#xff0c;我就一定要&#xff1b;假如我要&#xff0c;我就一定能&#xff01;&#x1f493;&#x1f493;&#x1f493; 目录 ✨说在前面 &#x1f34b;知识点一&#xff1a;树的概念和结构 • &#x1f330;1.什么是树&#x…

【漏洞复现】学分制系统GetTimeTableData SQL注入

0x01 产品简介 学分制系统由上海鹏达计算机系统开发有限公司研发&#xff0c;是基于对职业教育特点和需求的深入理解&#xff0c;结合教育部相关文件精神&#xff0c;并广泛吸纳专家、学者意见而开发的一款综合性管理系统。系统采用模块化的设计方法&#xff0c;方便学校根据自…

新奥集团校招面试经验分享、测评笔试题型分析

一、走进新奥集团 新奥集团成立于1989年&#xff0c;总部位于河北廊坊&#xff0c;是中国领先的清洁能源企业集团。业务涵盖城市燃气、能源化工、环保科技等多个领域&#xff0c;致力于构建现代能源体系&#xff0c;提升生活品质。 二、新奥集团校招面试经验分享 新奥集团的…

浔川AI3款产品同步上线——浔川AI社

第一款&#xff1a;浔川AI翻译v3.0 正式代码&#xff1a; # -*- coding: utf-8 -*- import tkinter as tk import tkinter.messagebox import pickle import random# 窗口 window tk.Tk() window.title(AI翻译登录界面) window.geometry(450x200) # 画布放置图片 # canvastk…

小程序驾校预约系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学员管理&#xff0c;教练管理&#xff0c;驾校信息管理&#xff0c;驾校车辆管理&#xff0c;教练预约管理&#xff0c;考试信息管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;驾校信息&a…