1.3 海量数据去重的Hash与BloomFilter,bitmap
本博客总结自零声教育的课程
本博客将和大家一起学习海量数据去重的hash的相关知识,包括海量数据查找的应用场景、平衡二叉树、hash冲突、hash聚集、如何解决hash冲突、布隆过滤器、怎么选择hash函数、分布式一致性hash存在的问题及解决方法等
知识树
1、海量数据查找的应用场景
(1)使用word文档时,word如何判断某个单词是否拼写正确?
(2)网络爬虫程序,怎么让它不去爬相同的url页面?(将url当作key,记录key,查找key来判断是否已经爬取过该url)
(3)垃圾邮件过滤算法如何设计?
(4)公安办案时,如何判断某嫌疑人是否在网逃名单中?
(5)缓存穿透问题如何解决?
★★★需求:从海量数据中查询某个字符串是否存在
2、平衡二叉树
平衡二叉树全称为平衡二叉搜索树
1、增删改查的时间复杂度为O(log2n)(平衡性使得时间复杂度稳定)
2、平衡的目的是:增删改后,保证下次搜能稳定排除一半的数据
3、O(log2n)的直观理解:
①如果有100万个结点,最多比较20次:n为100万,log2 n = log10 n / log10 2 = 6 / 0.301 = 20(小于20),因此最多比较20次
②如果有10亿个结点,最多比较30次:log2 n = log10 n / log10 2 = 9 / 0.301 = 30(小于30),因此最多比较30次
PS:O(log2n)已经很快了,再快就是O(1)了
总结:★平衡二叉树通过【比较】保证有序,通过每次排除一半的元素达到快速索引的目的
3、哪些算法涉及二分查找
1、AVL树是高度平衡的,左右子树的高度之差<=1;而红黑树只是黑高(黑色结点的高度相同)
2、平衡多路搜索树:★B+树的每个结点要和磁盘页相对应,为了快速索引磁盘,所以结点不能只存储一个元素而要存储多个元素,要和磁盘的页相匹配;可以用二分查找,因为每个叶子结点中的存储是顺序存储的(叶子结点中的元素是顺序排列的),从而可以用二分查找快速查找(平衡多路搜索树的时间复杂度为O(h*log2n))
因为平衡二叉树要
①存储元素
②比较字符串
所以,面对海量数据时平衡二叉树的时间复杂度就比较高了,因此平衡二叉树面对海量数据时是不被接受的
4、散列表
散列表 = 哈希 + 数组
散列表可以根据hash函数直接将key映射到存储地址(key =>存储地址):
映射函数Hash(key) = addr
(散列表较平衡二叉树的优点:避免了字符串的比较)
(1)hash冲突
映射函数Hash(key) = addr,hash函数可能会把两个或两个以上的不同key映射到同一地址,这种情况称为冲突(hash碰撞)
(2)负载因子
用来描述hash冲突的程度
1、负载因子 = 数组存储元素的个数 / 数据长度
2、负载因子用来形容散列表的存储密度;负载因子越小,冲突越小;负载因子越大,冲突越大
3、不同数据结构的负载因子不同,比如map中的负载因子是0.6几,redis中的负载因子为1
(3)解决hash冲突的方法
① 链表法(redis中、C++或JAVA中的unordered_map)
(1)引用链表来处理哈希冲突,也就是将冲突元素用链表链接起来(如上图)
(2)但是可能出现一种极端情况:冲突元素比较多,该冲突链表过长,这个时候会将我们的算法退化成O(n)
(3)解决:因此我们会将这个链表转换为红黑树或AVL树,为了将链表时间复杂度O(n)转换为红黑树时间复杂度O(log2n),以便快速查找(冲突不大时是O(1),冲突大时转化为红黑树或AVL树变为O(log2n));
(4)那么链表多长算过长呢?可以当超过256(经验值)个节点的时候将链表结构转换为红黑树结构
(5)插入新的冲突结点的时候,是插在链表的头部还是尾部:
①头插法 ②尾插法:
①头插法:用于数据库、redis、memcached等中,因为对于数据库而言,我们认为【最近插入的元素未来也会最先访问】
② 开放寻址法
将所有的元素都存放在哈希表的数组中,不使用额外的数据结构:数组中每个位置只存储一个元素: