1.哈希函数

1.1 特点:

  1. 经典的哈希函数输入域是无穷大的。
  2. 输出域是有穷尽的;
  3. 相同输入得到的输出肯定是一样的;
  4. 不同的输入得到的输出也可能一样(输入域>输出域);
  5. 哈希函数的离散型:给定多个不同的输入,得到的输出在输出域上均匀分布。
  • 可用来打乱输入规律,输出的规律和输入规律是没有关系的。
  • 若输出在整个输出域上均匀分布,那么输出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(哈希函数、哈希表、布隆过滤器、一致性哈希)相关推荐

  1. 给定一组查找关键字(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 ...

  2. 哈希表 哈希函数 时间_您需要了解的哈希函数

    哈希表 哈希函数 时间 安全从业人员的功能表中有一个工具可以帮助每个人理解,无论他们对计算机进行什么操作:加密哈希函数. 这听起来听起来像是神秘的,技术性的,甚至可能很无聊,但是我对什么是哈希以及它们 ...

  3. 哈希结构(图文详解)【哈希表,哈希桶,位图,布隆过滤器】

    哈希结构 哈希概念 常见的K-V结构,实现了元素关键码与元素值的映射关系,但没有实现元素关键值与元素存储位置的映射关系,在遍历过程中,一般的顺序表或搜索二叉树要进行关键值的多次比较,其中顺序表的时间复 ...

  4. 算法练习day12——190331(并查集)

    1.并查集 1.1 简介 用于解决检查两个元素是否属于一个集合: 合并两个元素各自所在的集合: 即: isSameSet(A,B):其中A属于set1,B属于set2,看set1和set2是否为同一个 ...

  5. 哈希的应用 -- 布隆过滤器与海量数据处理

    文章目录 布隆过滤器概念 布隆过滤器设计思路 布隆过滤器的应用 布隆过滤器模拟实现 布隆过滤器的基本框架 布隆过滤器的插入 布隆过滤器的探测 布隆过滤器的删除 布隆过滤器优点 布隆过滤器缺陷 布隆过滤 ...

  6. 哈希的应用 —— 布隆过滤器

    文章目录 布隆过滤器的提出 布隆过滤器的概念 布隆过滤器的实现 布隆过滤器的插入 布隆过滤器的查找 布隆过滤器的删除 布隆过滤器的优点 布隆过滤器的缺陷 布隆过滤器使用场景 布隆过滤器的提出 在注册账 ...

  7. 哈希思想的应用 - 位图,布隆过滤器

    目录 位图 海量数据处理问题: 哈希思想的应用:位图 位图实现: 位图处理海量数据 布隆过滤器 引: 布隆过滤器的概念: 布隆过滤器简单实现: 布隆过滤器的查找 布隆过滤器的删除 布隆过滤器优点 布隆 ...

  8. 高级数据结构与算法 | 哈希 :哈希冲突、负载因子、哈希函数、哈希表、哈希桶

    文章目录 哈希 哈希函数 常见的哈希函数 字符串哈希函数 哈希冲突 闭散列的解决方法 开散列的解决方法 负载因子以及增容 对于闭散列 对于开散列结构 具体实现 哈希表(闭散列) 插入 查找 删除 完整 ...

  9. 哈希算法(哈希函数)的基本使用

    哈希算法(哈希函数)的基本使用 什么是哈希? 哈希的原理和特点 数组与哈希表 哈希函数 哈希函数的冲突与碰撞 哈希算法 哈希的应用 什么是哈希? 如果我们需要誊抄一本新华字典,那么有什么方法呢?比如当 ...

最新文章

  1. Python学习之路基础篇--10Python基础,函数进阶
  2. 《LeetCode力扣练习》第56题 合并区间 Java
  3. SQL Server:Like 通配符特殊用法:Escape
  4. NDK学习笔记-使用现有so动态库
  5. 安装cleanmymac软件提示已损坏无法打开,如何解决?
  6. Android热修复更改图标,Android手写热修复(一)--ClassLoader
  7. webpack——文件和图片打包
  8. CCF NOI1138 高精度加法
  9. Cisco 防火墙 ASA DHCP 配置
  10. 如何给公司节约成本,搭建免费开源监控系统uptime-kuma
  11. Ubuntu 修改只读文件
  12. CSDN上传设置资源积分的霸王条款
  13. 做程序员10年有感,程序员必须要懂的---转自java诺曼底_kleen
  14. 80亿美元侵权诉讼的随想
  15. 淘宝商品点赞可以增加权重吗?
  16. srand(time(0))函数的用法介绍
  17. 北大才女笔记:这样学习线性回归和梯度下降(上篇)
  18. groovy提取时间戳
  19. 阿里云部署SpringBoot项目
  20. 物质模拟器1.1版 新增“老板键”

热门文章

  1. Spring Boot使用Spring Data Redis操作Redis(单机/集群)
  2. WinForm下的键盘事件(KeyPress、KeyDown)及如何处理不响应键盘事件
  3. golang文件操作
  4. Banana PI 香蕉派项目
  5. [python pycharm pytorch debug sets]
  6. harbor镜像清理:使用registry:2.6.2-photon garbage-collect
  7. arthas命令整理:基础命令、jvm相关、class相关命令
  8. docker容器间双向通信(基于Bridge网桥)
  9. Scala特质的动态混入(超强扩展性)
  10. Docker创建Dockerfile脚本构建jdk1.8镜像并启动容器示例