算法练习day12——190331(哈希函数、哈希表、布隆过滤器、一致性哈希)
1.哈希函数
1.1 特点:
- 经典的哈希函数输入域是无穷大的。
- 输出域是有穷尽的;
- 相同输入得到的输出肯定是一样的;
- 不同的输入得到的输出也可能一样(输入域>输出域);
- 哈希函数的离散型:给定多个不同的输入,得到的输出在输出域上均匀分布。
- 可用来打乱输入规律,输出的规律和输入规律是没有关系的。
- 若输出在整个输出域上均匀分布,那么输出mod m之后得到的结果在0~m-1上也是均匀分布的。
1.2 由给定的一个哈希函数得到1000个互相独立的哈希函数
假设给定哈希函数h,它的输出是16位的。
将其高8位作为h1,低8位作为h2。h1和h2相互独立,因为16位输出中的每一位都和其他位无关。
那么,可构造:
- ...
构造的多个哈希函数之间是相互独立的。
2.哈希表
2.1 put(K,V)
hashCode(K)-->h1
将(K,V)放到下标为h1的桶中:
- 若桶不空,则判断有无K;
- 有,V若不等,则更新V;
- 无,直接将(K,V)链在此桶元素的后面。
若桶中的链较长,需要扩容。
重新以新容量进行hashCode的运算。
各种操作都是级别的。即使扩容操作费时,但这操作不频繁,也可以押得很低。(还可在离线的时候进行扩容,不占用在线时间)。
JVM中每个桶中放的是一棵红黑树。不太需要扩容。
有一个100T的大文件,其中每一行存的是一个字符串,去掉其中重复的字符串。假设可用的机器为1000台。
具体做法:
用哈希函数作分流——读出每一行字符串,然后进行hashCode计算,之后模1000。这样相同的字符串就会分配到同一台机器。——利用哈希函数可以将100T大文件中的字符串(假设M种 )按种类平均分配到1000台机器上。
3.设计RandomPool结构
【题目】 设计一种结构, 在该结构中有如下三个功能:
- insert(key): 将某个key加入到该结构, 做到不重复加入。
- delete(key): 将原本在结构中的某个key移除。
- getRandom():等概率随机返回结构中的任何一个key。
【要求】 Insert、 delete和getRandom方法的时间复杂度都是O(1)
3.1 分析
哈希表的结构中:
- 若数据量较少,有的桶可能会没元素,此时无法做到均匀取出(遍历取出的话,复杂度会达到O(N))
- 若数据量较多,每个桶中的链长度也不是绝对相等的。无法做到等待率。
本题中使用两个哈希表map1和map2实现。
比如A元素是第0个进来的,那么:
- 在map1中就存(A,0)——A是第0个进来的;
- 在map2中存(0,A)——第0个进来的是A。
同时需要有个int型的变量记录某个元素是第几个进来的。
3.1.1 先考虑add(),忽略remove()。
- 若目前进来了26个元素,size=26,此时调用了getRandom():
- 使用Math.random()*size生成0~25中随机一个数indexm;
- 然后在map2中由Key=index找到对应的value,返回 。
3.2.1 remove()
若删除时不做任何操作,则在删除之后,会产生多个“洞”,使得在计算index时无法做到等概率,因为某些位置上没元素。
假设有1000条记录(str0~str999),现在要删除str17,在删除时:
- map1中:将str999放在str17的位置(即,将自己的value改为17即可);
- map2中:将str999放在17的位置上(即,将自己的key改为17即可,也就是将17对应的value由str17改为str999);
- 删除map1和map2中的最后一条记录;
- size-1=999.
保证了存储数据位置的连续。
3.2 代码实现
package Hash;import java.util.HashMap;public class RandomPoolTest {public static class RandomPool{HashMap<String,Integer> map1;HashMap<Integer,String> map2;int size;public RandomPool() {this.map1=new HashMap<>();this.map2=new HashMap<>();this.size=0;}public void insert(String str) {if(!this.map1.containsKey(str)) {this.map1.put(str, this.size);this.map2.put(this.size, str);this.size++;}}public void delete(String str) {if(this.map1.containsKey(str)) {int index=this.map1.get(str);String laststr=this.map2.get(--this.size);this.map1.put(laststr, index);this.map2.put(index, laststr);this.map1.remove(str);this.map2.remove(index);size--;}}public String getRandom() {if(size==0)return null;int index=(int)(Math.random()*size);return this.map2.get(index);}}
}
4.布隆过滤器
4.1 简介
应用场景:判断某一个东西是否在一个集合中(布隆过滤器本身就是一个集合)
举例:看一个url是否在已有的黑名单(100亿个64字节的url)中,在返回true,不在返回false。
若使用哈希函数,不存value,则使用HashSet,最起码需要6400亿字节(640G)才能把所有的黑名单url装下。
缺点:有失误率
- 若一个url确实属于黑名单,则它肯定返回true;
- 若一个url不在黑名单中,可能返回true,也可能返回false。
布隆过滤器是一个比特类型的map
int[] arr=new int[1000];
//一个整型是4个字节,32个比特,则int[] arr=new int[1000];一句申请了32000个比特位int index=30000;int intIndex=index/32;//由除数定位到给定的数在哪个桶中(一个桶32bit)
int bitIndex=intIndex%32;//由余数定位到给定的数在桶中的具体哪个比特位上
arr[intIndex]=arr[intIndex]|(1<<bitIndex);
1左移16位=num——>只有第16位上为1,其余为0;
arr[937]和num进行或运算,则num的第16位就置为1了——表示30000这个值在集合中存在了。
怎么得到比特数组?
用基础类型拼,类似于前面的int[1000]——32000个比特位;
若给定的index太大,可换为long[1000]——64000个比特位;
若还是很大,可换为long[1000][1000]——1000*1000*64个比特位。
4.2 上面黑名单的实现
4.2.1 分析
一个url进入布隆过滤器的过程:
- 先使用哈希函数h将url变为一个hashcode,
- 然后hashcode%m得到一个范围在0~m-1的值;
- 将得到的值对应于数组的位置上的值置为1.
- 布隆过滤器是使用k个哈希函数h1~hk,计算k个hashcode,将得到的k个位置上的值置为1.
查一个url是否在黑名单中:
- 将这个url进入k个哈希函数的运算,得到k个值;
- 在给定的数组中查看这k个值对应的位置是否都为1;
- 若都为1,返回true;
- 否则返回false。
数组范围应长一点,要不100亿个url进去之后,几乎所有的位置都已置为1了,无法查询——所有的url查询都会返回true。
- 空间越大,失误率越低;
- 空间越小,失误率越高。
哈希函数的个数k,只和url个数有关系,和url具体大小,多少字节无关。
比特数组大小m的计算公式:
- n:样本量——100亿;
- p:预期失误率——万分之一0.0001
- m:单位是bit,算出来小数的话,向上取整。
k也是向上取整
当k和m向上取整之后,真实的错误率为:
【当给定题目后,首先给出经典解法,——占用空间太大——允不允许失误率?——允许——讲解布隆过滤器、算出m(在给定范围内尽量大),K,再算出真正的失误率,比给定的失误率要低——】
若在乎I/O,则将m内存分布式存储;
5.一致性哈希
5.1 经典服务器抗压结构
当需要加减机器的时候,这个结构就不合适了。所有已存储的数据归属全变了。
——引入了一致性哈希结构
5.2 一致性哈希
可降低数据迁移的代价,同时又负载均衡。
将哈希函数的返回值()想象为一个环:
有3台机器m1、m2、m3,假设它们是以IP进行区分的。
- 将m1、m2、m3的IP串经过哈希运算,对应到环上一点。
假设存储(zuo,31),将zuo 进行哈希运算后,不用进行模运算,直接对应到环上一点:
顺时针找到离zuo在环上这一点最近的机器(m2),将(zuo,31)存储在此机器上。
查的时候也一样。
5.2.1 实现
后端还是三台机器,前端还是无差别的负载服务器。
将m1、m2、m3的哈希值排序(有小到大)后组成一个数组{m1,m2,m3},将这个数组存到前端的每一个服务器中。
当zuo进来后,以二分查找的方式确定它在那个机器上:
- 知道第一个大于等于zuo的哈希值的机器哈希值(以顺时针选的机器)。
现在需要添加一个机器m4,将它的IP经过哈希运算映射到如图所示的点中:
则需要做数据迁移的部分如图所示:
哈希函数的性质保证的是:量多的情况下,机器数据量均分。
这种结构存在的问题是,机器负载会不均衡。
虚拟节点技术可以解决这个问题。
5.3 虚拟节点技术
有三台机器:m1、m2、m3
给每个节点分配1000个虚拟节点:
- m1:m1-1,m1-2,m1-3,...
- m2:...
- m3:...
准备一个物理映射表:
- 可以从表中得知一个机器有哪些节点;
- 也可知道一个节点属于哪个机器。
令这3000个虚拟节点抢环上的位置,由虚拟节点负责的域,实际上是让它属于的实际机器去处理。——这样就使得三台机器负责的区域是差不多的。
加机器m4时,它也拥有1000个虚拟节点,这些虚拟节点进环,瓜分之前节点的负责的区域。
淡化物理机器的概念,强调虚拟节点的概念。
5.5 应用场景
用到集群特性,抗压的
算法练习day12——190331(哈希函数、哈希表、布隆过滤器、一致性哈希)相关推荐
- 给定一组查找关键字(19,14,23,1,65,20,84,27,55,11,10,79) 哈希函数为:H(key)=key % 13, 哈希表长为m=15,设每个记录的查找概率相等。【MOOC】
目 录 题 目①[关键字(19, 14, 23, 1, 65, 20, 84, 27, 55, 11, 10, 79)] 解法一(线性探测再散列) 解法二(链地址法) 题 目②[关键字(19, 1 ...
- 哈希表 哈希函数 时间_您需要了解的哈希函数
哈希表 哈希函数 时间 安全从业人员的功能表中有一个工具可以帮助每个人理解,无论他们对计算机进行什么操作:加密哈希函数. 这听起来听起来像是神秘的,技术性的,甚至可能很无聊,但是我对什么是哈希以及它们 ...
- 哈希结构(图文详解)【哈希表,哈希桶,位图,布隆过滤器】
哈希结构 哈希概念 常见的K-V结构,实现了元素关键码与元素值的映射关系,但没有实现元素关键值与元素存储位置的映射关系,在遍历过程中,一般的顺序表或搜索二叉树要进行关键值的多次比较,其中顺序表的时间复 ...
- 算法练习day12——190331(并查集)
1.并查集 1.1 简介 用于解决检查两个元素是否属于一个集合: 合并两个元素各自所在的集合: 即: isSameSet(A,B):其中A属于set1,B属于set2,看set1和set2是否为同一个 ...
- 哈希的应用 -- 布隆过滤器与海量数据处理
文章目录 布隆过滤器概念 布隆过滤器设计思路 布隆过滤器的应用 布隆过滤器模拟实现 布隆过滤器的基本框架 布隆过滤器的插入 布隆过滤器的探测 布隆过滤器的删除 布隆过滤器优点 布隆过滤器缺陷 布隆过滤 ...
- 哈希的应用 —— 布隆过滤器
文章目录 布隆过滤器的提出 布隆过滤器的概念 布隆过滤器的实现 布隆过滤器的插入 布隆过滤器的查找 布隆过滤器的删除 布隆过滤器的优点 布隆过滤器的缺陷 布隆过滤器使用场景 布隆过滤器的提出 在注册账 ...
- 哈希思想的应用 - 位图,布隆过滤器
目录 位图 海量数据处理问题: 哈希思想的应用:位图 位图实现: 位图处理海量数据 布隆过滤器 引: 布隆过滤器的概念: 布隆过滤器简单实现: 布隆过滤器的查找 布隆过滤器的删除 布隆过滤器优点 布隆 ...
- 高级数据结构与算法 | 哈希 :哈希冲突、负载因子、哈希函数、哈希表、哈希桶
文章目录 哈希 哈希函数 常见的哈希函数 字符串哈希函数 哈希冲突 闭散列的解决方法 开散列的解决方法 负载因子以及增容 对于闭散列 对于开散列结构 具体实现 哈希表(闭散列) 插入 查找 删除 完整 ...
- 哈希算法(哈希函数)的基本使用
哈希算法(哈希函数)的基本使用 什么是哈希? 哈希的原理和特点 数组与哈希表 哈希函数 哈希函数的冲突与碰撞 哈希算法 哈希的应用 什么是哈希? 如果我们需要誊抄一本新华字典,那么有什么方法呢?比如当 ...
最新文章
- Python学习之路基础篇--10Python基础,函数进阶
- 《LeetCode力扣练习》第56题 合并区间 Java
- SQL Server:Like 通配符特殊用法:Escape
- NDK学习笔记-使用现有so动态库
- 安装cleanmymac软件提示已损坏无法打开,如何解决?
- Android热修复更改图标,Android手写热修复(一)--ClassLoader
- webpack——文件和图片打包
- CCF NOI1138 高精度加法
- Cisco 防火墙 ASA DHCP 配置
- 如何给公司节约成本,搭建免费开源监控系统uptime-kuma
- Ubuntu 修改只读文件
- CSDN上传设置资源积分的霸王条款
- 做程序员10年有感,程序员必须要懂的---转自java诺曼底_kleen
- 80亿美元侵权诉讼的随想
- 淘宝商品点赞可以增加权重吗?
- srand(time(0))函数的用法介绍
- 北大才女笔记:这样学习线性回归和梯度下降(上篇)
- groovy提取时间戳
- 阿里云部署SpringBoot项目
- 物质模拟器1.1版 新增“老板键”
热门文章
- Spring Boot使用Spring Data Redis操作Redis(单机/集群)
- WinForm下的键盘事件(KeyPress、KeyDown)及如何处理不响应键盘事件
- golang文件操作
- Banana PI 香蕉派项目
- [python pycharm pytorch debug sets]
- harbor镜像清理:使用registry:2.6.2-photon garbage-collect
- arthas命令整理:基础命令、jvm相关、class相关命令
- docker容器间双向通信(基于Bridge网桥)
- Scala特质的动态混入(超强扩展性)
- Docker创建Dockerfile脚本构建jdk1.8镜像并启动容器示例