左神算法-初级6(python)

哈希函数和哈希表

哈希函数

哈希函数性质:

① 输入域无穷大
② 输出域有限
③ 输入一样,输出一样
④ 哈希碰撞
⑤ 离散性(输入域经过哈希函数在输出域上均匀分布),输出域模一个数k,得到的结果还是均匀分布。

哈希函数特点:

输出和输入无关(打乱输入规律)

生成1000个相对独立的哈希函数:

假设哈希函数的输出域是h,那么输出域的前一半h1和后半h2可以形成2个独立的哈希函数,
然后 h1 + ih2 可以形成1000个相对独立的哈希函数(i取任意值)
可以使用一个哈希函数作为种子;
也可以使用两个作为种子来组合。
可以把哈希函数结果每一位理解为一个独立的哈希函数,因此哈希函数结果可以看作若干哈希函数的组合。
以MD5为例,其结果可以看作16个哈希函数的组合。

哈希表

put(key1, value)
get(key1)
remove(key1)
增删改查的时间复杂度默认为 O(1)

哈希扩容:首次生成一个空间g,形成g个桶,结构为链表(其他也可以,java的是红黑树),n个(key,value)
的key经过哈希函数,然后模g(%g)挂到对应的空间,当链达到一定程度时(过长影响时间复杂度,这里每个链的长度大致相同,因为哈希后均匀分布),需要扩容:
扩容可以成k倍扩容,那么需要扩容到n,需要logk(n)(时间复杂度 O(logk(n))),
还可以离线扩容(一边在原空间做哈希,同时在新空间(后台)做哈希并且把原空间数据转移,数据转移结束前,用户仍然访问旧空间,并不影响使用和时间复杂度)。

设计 RandomPool 结构

# 该结构三个功能:
'''
insert(key)
delete(key)
getRandom()
时间复杂度均为 O(1)

使用两张哈希表实现
map1                           map2
key   value       index        value   key
A     0           0            0       A
'''
import random
 
def RandomPool(string):
    map1 = {}
    map2 = {}
    size = 0
    def add(string, size):
        for i in string:
            map1[i] = size
            map2[size] = i
            size += 1
        print('添加元素后map1:\n ', map1.keys(), '\n ', map1.values(), '\n ', size, '\n ')
        print('添加元素后map2:\n ', map2.keys(), '\n ', map2.values(), '\n ', size, '\n ')
        return size
    
    def insert(string, size):
        if map1[string] == None:
            map1[string] = size
            map2[size] = string
            size += 1
    
    def delete(s, size):
        index = map1.get(s)
        del map1[s]
        del map2[index]
        if index != (size-1):
            # 把最后一个放入删除位置,size - 1
            tmp = map2[size-1] 
            del map2[size-1]
            map1[tmp] = index
            map2[index] = tmp
        size -= 1
    
    def getRandom(size):
        if size == 0:
            return None
        # random() 方法返回随机生成的一个实数,它在[0,1)范围内
        index = int(random.random()*size)
        print('随机得到一个键:', index)
        return map2.get(index)
    
    
    size = add(string, size)
    print('随机得到一个值:', getRandom(size), '\n ')
    delete('e', size)
    print('删除一个元素后map1:\n  ', map1.keys(), '\n  ', map1.values(), '\n  ', size)
    print('删除一个元素后map2:\n  ', map2.keys(), '\n  ', map2.values(), '\n  ', size)
    
            
string = str('abcdefg')
RandomPool(string)

查找大文件中重复字符串:基本原理是哈希分流
原理:相同输入相同输出,不同输入均匀输出
M台电脑
把每行数据经过哈希函数后,模 M(%M),均分到M台电脑上
因为输入一样,输出一样
所以同样的数据会存到一台电脑内(如果数据还是比较大,继续分流)

布隆过滤器

64位系统和32位有什么区别?
1、64bit CPU拥有更大的寻址能力,最大支持到16GB内存,而32bit只支持4G内存
2、64位CPU一次可提取64位数据,比32位提高了一倍,理论上性能会提升1倍。但这是建立在64bit操作系统,64bit软件的基础上的。

什么是64位处理器?
之所以叫做“64位处理器”,是因为电脑内部都是实行2进制运算,处理器(CPU)一次处理数据的能力也是2的倍数。
8位处理器、16位处理器、32位处理器和64位处理器,其计数都是2的倍数。
一次处理的数据越大,该电脑处理信息的能力越来越大;因此64位处理在先天就比32位处理器具有快速的能力。
那为什么不用更高级的128位处理器呢?因为位数越高,处理器芯片的设计也就越复杂,目前的技术水平暂时无法制造这么复杂的芯片。

int类型和float 都占用4个字节,一个字节占8个bit,也就是一个int32位

题目】:
不安全网页的黑名单包含100亿个黑名单网页,每个网页的URL最多占用64B。现在想要实现一种网页过滤系统,
可以根据网页的URL判断该网页是否在黑名单上,请设计该系统。

要求】如下:
1、该系统允许有万分之一以下的判断失误率。
2、使用的额外空间不要超过30GB。
如果将这100亿个URL通过数据库或哈希表保存起来,就可以对每条URL进行查询,但是每个URL有64B,
数量是100亿个,所以至少需要640GB的空间,不满足要求2。

So:
布隆过滤器
系统容忍一定程度的失误率,但是对空间要求比较严格,那么很可能是面试官希望面试者具备布隆过滤器的知识。

一个布隆过滤器精确地代表一个集合,并可以精确判断一个元素是否在集合中。

那么什么是布隆过滤器呢?
产生阶段:
假设有一个长度为m的bit类型的数组,即数组的每个位置只占一个bit,每一个bit只有0和1两种状态;
再假设一共有k个哈希函数,这些函数的输出域S都大于或等于m,并且这些哈希函数彼此之间相互独立;
对同一个输入对象(假设是一个字符串,记为URL),经过k个哈希函数算出来的结果也是独立的。可能相同,也可能不同,但彼此独立。
对算出来的每一个结果都对m取余(%m),然后在bit array 上把相应位置设置为1(可能多次,没关系);
接下来按照该方法,处理所有的输入对象,至此,一个布隆过滤器生成完毕,这个布隆过滤器代表之前所有输入对象组成的集合。

在检查阶段时,用同样的方法计算得到k个值,在bit array 上查看相应位置设置是否为1;
如果有一个不为1,说明a一定不再这个集合里。如果都为1,说明a在这个集合里,但可能误判。
会产生误判的是生成布隆过滤器的阶段因为输入对象过多,而bitMap过小(哈希碰撞)。

bitMap空间大,查找失误率会比较小。
bitMap空间大小和样本个数(url的个数)有关,和单个url的大小无关;也和失误率有关。
bitMap空间大小:m = n*ln§ / (ln2)^2 = 131 571 428 572, n:样本量, p=0.00001
m的单位是bit,除以8得到字节,也就是需要的空间,m/8 = 22 346 428 571.5 = 23G
1kb=1024字节, 1MB=1024KB, 1GB=1024MB

哈希函数个数:k = ln2*(m/n) = 13(向上取整)
由于前两步都进行了向上取整,最终真实失误率:p = (1 - e(-nk/m))k = 6/10万

认识一致性哈希

哈希扩容、数据迁移、负载均衡

为了避免哈希扩容时,全部数据迁移造成浪费:
让有限哈希函数的输出域组成一个环,这样扩容时,不需要所有数据重新哈希,只需要离新添加哈希函数最近的哈希函数
数据的一部分重新计算就可以了
但是,哈希函数比较少时,数据就不一定在环上均匀分布,或者添加哈希函数和去除哈希函数会造成环上数据不均匀,都会造成负载不均衡
解决方法:虚拟节点
每个机器设置1000个虚拟节点,落在每个虚拟节点的数据归于所属物理机,这样数据就大致均匀分布了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值