10.基础提升 哈希函数与哈希表等_哔哩哔哩_bilibili 的学习笔记
哈希函数f的特征:
相同的输入一定导致相同的输出
不同的输入 导致不同的输出(有可能有碰撞)
输出是均匀分布的
in—(f函数)-out —(%m取模)—新的输出在0~m-1上均匀分布
哈希表:
基于哈希函数实现的,哈希表是均匀变长的
查找的时候通过哈希函数知道是去哪个桶(k个桶)里找 复杂度:O(k)~O(1)
每个桶链长度不超过2,扩容要logN,不超过k,扩容要logkN,
扩容:每个数据计算哈希值,全要去挂桶,加了N个字符串代价是O(N*logkN) k大点就看作每个O(1)
虚拟机:可用离线扩容机制(除去C++)
另外:开放地址法
设计RandomPool 结构
[题目]
设计一种结构,在该结构中有如下三个功能:
insert (key) :将某个key加入到该结构,做到不重复加入
delete (key) :将原本在结构中的某个key移除
getRandom() :等概率随机返回结构中的任何一个key。
[要求]
Insert、 delete和getRandom方法的时间复杂度都是0(1)
结构里需要这三个
map1(str->index)
map2(index->str)
intsize
ABC…Z 0~25
getRandom:
没有删除行为时:随机生成数0~intsize-1
有删除行为时:最好保证index上没有空洞,让最后一条记录(intsize上有)去填要删的地方,--intsize;
布隆过滤器
不会出现 黑名单误报白名单
只会可能 白名单误报黑名单
好处:极大的省空间
坏处:失误率很低 万分之一但不可避免
怎么实现?:
位图
bit arr/bit map
基础类型数组eg:int(4字节)—->建立bit类型数组
int[] arr = new int[10]; 32bit*10->320bit
int i = 178;//获得178个bit的状态
int numIndex = 178/32;//定位哪个数
int bitIndex = 178%32;//具体这个数的哪一位的信息
int s = ( (arr[numIndex]) >> (bitIndex)) &1
//这个数右移bitindex位,第178位的信息在这个数的最右侧,再与1&操作,就得到178位的状态
arr[numIndex] = arr[numIndex] | (1 << bitIndex)
//把第178位的状态改为1,,,将原始的信息 或操作 1左移bitindex位 后的状态
arr[numIndex] = arr[numIndex] & (~ (1 << bitIndex))
//将第178位的状态改为0
布隆过滤器的实现:
(Url:web地址)
大位图 长度为m bit数组占用m/8字节的内存
对于黑名单的第一个url1 :
U1分为几个特征块
——(fun1)——out1——(%m)——得到它是哪个格,描黑
——(fun2)——out2——(%m)——得到它是哪个格,描黑
……
k个哈希函数,得到k个位置,可能会出现某两个位置一样
然后对Url2同样的操作……到Url100亿
就建立好了
urlx 调用k个哈希函数得到哈希值取模,看看相对应的位置是否全都描黑,若有一位没有的话,说明这个urlx不在黑名单里
其中:k和m是不确定的
位图开的很大很大,m越大,越不容易失误。再根据样本数和url的特征数 去设置一个合适的k。。。(k越大,m个格中描黑的越多)
失误率随m的增大逐渐降低,失误率随k的增大先降低后急剧升高。
计算公式:(条件:样本量n,失误率P)
m = -(n*ln P)/((ln 2)^2)
k = ln2*m/n~~0.7*m/n;
实际失误率:
一致性哈希问题
哈希key,选择类别较多的,使得高频中频低频的都有一定的数量 (负载均衡算法,将数据均匀的分配到各个机器上,防止有的机器忙到崩溃,而有的机器闲)
一致性哈希:没有模运算
假设使用哈希函数MD5算法,返回值0~2^64-1
将整个哈希域想象成一个环
假设有三台机器m1,m2,m3,是用来存数据的,三台机器的host name不一样,我们用这个来做机器的哈希值,得到的数据放在这个环上,三台机器插到环上
假设将‘左,33岁’这个信息通过哈希函数,会对应到环上的某个位置,通过顺时针找到最近的机器。
怎样知道是最近的是哪个机器:有逻辑端服务器,是要实现数据分配,三台机器的哈希值排序存放在逻辑服务器
增加机器:通过哈希函数找到对应环上的位置,接管顺时针以前的数据
增加/减小机器数据迁移的代价很明显降低了,但是存在问题: 1.机器数量很少的时候很难做到在环上的均衡,2.即使机器在环上均衡了,但是增加/减少机器时,负载依旧不均衡;
解决方法:虚拟节点技术
m1机器分配1000个字符串a1,a2,..,a1000
m2机器分配1000个字符串b1,b2,..,b1000
m3机器分配1000个字符串c1,c2,..,c1000
虚拟节点去抢环上的位置,m1有1000个代表字符串,每一个字符串计算哈希值去抢环,m2,m3
虚拟节点上的数据迁移,比如说a1000上的数据给b500怎样实现: a1000去m1上找数据,找到之后给m2,作为m2上第500位置的数据
同样的,增加/减少机器m也分配1000个字符串
要是m1机器性能较好,我们可以将m1分配的字符串增加到a2000.让它多处理点数据