哈希函数和哈希表
Hash函数的性质:输入无穷大,输出有限,相同输入得到相同输出,不同输入可能会出现相同输出,输入到输出均匀分布,相差一点的输入输出相差很大。哈希函数加上模运算可以进行数据的分流操作。
哈希表:数据存储和检索当中使用哈希表的作用是将一个非常大的空间映射到一个可以接受的存储空间当中,在检索一个值的时候时间复杂度为O(1),并且存储空间可接受。假如要存储一个长度为10的字符串,它可能的情况为26^10 = 1.4 * 10^14种,假如一一映射的话,需要很大的存储空间,这显然是不合适的。
设计哈希表要考虑两块内容,一块内容是如何设计映射函数,另一块内容是当出现冲突的时候如何解决这个冲突(因为从大到小映射,冲突是必然的),叫做冲突的消解机制。围绕这两个问题,可以设计出来实际可用的哈希算法。
散列函数:对于整数有:数字分析法、折叠法、中平均法。 常用散列函数:除余法,基数转换法。
冲突消解机制:内消解方法(开放地址法+探查序列)。外消解技术主要有:溢出区方法,桶散列方法。
设计RandomPool结构
【题目】 设计一种结构, 在该结构中有如下三个功能:insert(key): 将某个key加入到该结构, 做到不重复加入。delete(key): 将原本在结构中的某个key移除。 getRandom():等概率随机返回结构中的任何一个key。
【要求】 Insert、 delete和getRandom方法的时间复杂度都是O(1)
【思路】用两个hash表来实现,一个表存入{key:size},另外一个表存入{size:key}。这样随机获得size的大小来随机获得一个key。这里的稍微有点绕的地方是删除一个数据的时候操作过程。
import random class random_dict(object): def __init__(self): self.key_dict = {} self.value_dict = {} self.size = 0 def insert(self, key): if not key in self.key_dict: self.key_dict[key] = self.size self.value_dict[self.size] = key self.size += 1 def get_random(self): if self.key_dict: random_num = random.randint(0, self.size-1) return self.value_dict[random_num] def delete(self, drop_key): """ a -> 1 1->a b -> 2 2->b c -> 3 3->c 如果想要删除b,那么如何进行 根据b,得到2 | 根据2 得到b' | b'用最后一个元素代替 | c指向2 | 删除b和3 """ if drop_key in self.key_dict: self.size -= 1 drop_size_index = self.key_dict[drop_key] last_value = self.value_dict[self.size] self.value_dict[drop_size_index] = last_value self.key_dict[last_value] = drop_size_index del self.key_dict[drop_key] del self.value_dict[self.size]
布隆过滤器
布隆过滤器是解决:在一个数据量很大的范围内检索一个数值是不是存在。
优点: 使用内存小,查找为O(1)的时间操作。
缺点:会出现误报的情况(假如一个数据不在里面,可能会查出来说它在里面,但假如一个数据真的在里面,不会出现漏掉的情况,它一定会查找出来。)
布隆过滤器使用了多个哈希表还有bit位来进行存储。
布隆过滤器(Bloom Filter)详解 介绍了布隆过滤器还有三个公式。
一致性hash
一致性hash和虚拟节点都是为了解决:均衡负载而设计的。
传统的hash然后求模的分流方式在进行增加和删除的时候需要大规模的移动数据,一致性hash在增加和删除节点时只需要移动少量数据。虚拟节点是为了解决各个节点负载不均衡的问题而设计的。
每天进步一点点——五分钟理解一致性哈希算法(consistent hashing)
并查表
岛问题
一个矩阵中只有0和1两种值, 每个位置都可以和自己的上、 下、 左、 右四个位置相连, 如果有一片1连在一起, 这个部分叫做一个岛, 求一个矩阵中有多少个岛?
【思路】访问过的岛标记为2
【分布式岛问题】假如要使用分布式的方式来进行解决,那么可以使用并查表来实现,但是这里的难点在于如何将单步得到的并查表何在一起。单步可以得到岛的数目还有并查表的信息,比较边界并查表的信息,假如两个节点不在一个并查表,那么将他们合并,并且岛的数目减1。
def get_island_num(island): col = len(island) row = len(island[0]) island_number = 0 for i in range(col): for j in range(row): if island[i][j] == 1: island_number += 1 find_same_island(island, i, j, col, row) return island_number def find_same_island(island, i, j, col, row): if(i< 0 or i >=col or j <0 or j >=row or island[i][j]!=1): return island[i][j] = 2 find_same_island(island, i+1, j, col, row) find_same_island(island, i-1, j, col, row) find_same_island(island, i, j+1, col, row) find_same_island(island, i, j-1, col, row) if __name__ == '__main__': map1 = [[ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 1, 1, 1, 0, 1, 1, 1, 0 ], [ 0, 1, 1, 1, 0, 0, 0, 1, 0 ], [ 0, 1, 1, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1, 1, 0, 0 ], [ 0, 0, 0, 0, 1, 1, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ]] map2 = [ [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 1, 1, 1, 1, 1, 1, 1, 0 ], [ 0, 1, 1, 1, 0, 0, 0, 1, 0 ], [ 0, 1, 1, 0, 0, 0, 1, 1, 0 ], [ 0, 0, 0, 0, 0, 1, 1, 0, 0 ], [ 0, 0, 0, 0, 1, 1, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ]]; print(get_island_num(map1)) print(get_island_num(map2))