概念
扩展或收缩哈希表需要将 ht[0]
里面的所有键值对 rehash 到 ht[1]
里面, 但是, 这个 rehash 动作并不是一次性、集中式地完成的, 而是分多次、渐进式地完成的。
那么为什么要这么做呢,如果这时候我的哈希表里的节点数据很多大到几十万百万的话,将这些键值对全部 rehash 到 ht[1]
的话, 庞大的计算量可能会导致服务器在一段时间内停止服务。
rehash整体过程:
1、字典的数据结构里有ht这个哈希表的引用,就是 ht[0]
和 ht[1]
两个哈希表。
2、字典的数据结构里dictht里有个rehashidx字段是维护我们rehash的进度的,默认是-1,设置成0就标识开始rehash了,在后面每一次rehash就会+1,直到rehash完成在设置成-1
3、rehash的过程中会对used和dictEntry操作扩容或者缩容,首先会分配一个ht[1]空间,根据2的n次方幂等方式,比如一开始我used=4,那么4*2=8下一个dictEntry容量就是8扩容,每一次渐进的时候都会把原来ht[0]的dictEntry节点指向NULL,在赋值给ht[1],最终在把完成ht[1]后的替换为ht[0],在把ht[1]创建一个空哈希表,这样整个rehash就算完成。
下面是rehash的完成过程
1、准备rehash
这时候是刚要进行rehash,还未开始的时候rehashidx=-1,dictEntry=4
2、开始reahsh第一步
这时候开始rehash,rehashidx=0,把ht[0]的dictEntry节点k1的设置为null,ht[1]的dictEntry扩容为=8的并且把k1的赋值给ht[1]的dictEntry
3、最后rehash完成前
这时候基本上已经把ht[0]的dictEntry都赋值给了ht[0]了,基本已经完成
4、最后完成rehash
rehash过程请求数据怎么处理的
因为在进行渐进式 rehash 的过程中,会存在 ht[0]
和 ht[1]
两个哈希表, 所以期间所有操作两个哈希表上进行,会先在 ht[0]
里面进行查找再就会继续到 ht[1]
里面进行查找。
另外, 在新增键值对保存到 ht[1]而不会新增到
ht[0],
这就是符合后面的rehash的过程了,不然你又保存到了ht[0]了就会产生数据不一致了