前言
首先什么是可扩展哈希(Extendible Hashing)?
我们平常用的hash都是静态hash,比如一个数字想存入hash表中,先经过hash函数,然后将其存入对应的hash表中,注意这个hash表是一个静态的,其大小在创建之初就固定好了的,那么随着我们存入的数据越来越多,hash表的也越来越慢,冲突率也越来越大,我们最好维持hash表中元素的个数占总hash表容量的百分之七十,这样才能保持低的冲突率,此时我们就用到动态hash,也就是我们的可扩展hash
可扩展hash结构
可扩展hash有2种结构,分别是
- directory:是一个可扩展数组,每一个数组元素都存储着一个bucket的指针,directory每一个元素都有一个独一无二的id,这个id有意思,是一个二进制数
- bucket:这个只要是hash表都有,用于存储hash表中的数据,换句话说多个bucket组成hash表
- global depth:这个东西和directory有关系,因为directory的每个数组元素都有一个独一无二的id,这个id是二进制bit组成比如1,11,011,而global depth代表你的directory id有一个bit,比如我们的global depth为3,那么对应directory id最多取到111,说明directory id最多为7,也就是最多8个数组元素
- local depth:和global差不多,但是local depth是对应bucket,local depth总是小于等于global depth
关于bucket,当一个bucket中的元素个数超过规定个数,此时bucket会发生分裂(bucket splitting)
关于Directory,当bucket发生分裂,directory也会发生expansion
可扩展hash的过程
我们传统静态hash的过程是hash函数后直接将值存入对应的bucket,但是在可扩展hash中,首先经过hash函数存入Directory中,再由directory指向对应的bucket,具体过程如下
-
分析待hash的key的类型,也许是int,也许是string,也许是float等等,假设我们的key就是int类型数字49
-
将key转换成二进制的形式,49转换成二进制为110001
-
check global depth ,假设global depth为3
-
选择对应的directory,怎么选择呢?我们的49二进制为110001一共6位,而global depth为3,只需要3位,此时我们截取110001的最后三位001作为directory id
-
开始定位到对应的bucket中
-
开始插入元素,再check bucket是否overflow
7. 假如overflow,且 对应bucket的local depth 等于global depth则都加一,然后重新hash overflow的bucket注意global depth加一后会多出非常多的元素,此时我们需要将这些多出来的数组元素指向local depth小于global depth的bucket上
- 假如overflow 且对应的bucket的loacl depth 大于global depth,则只用给对应bucket的local depth加一然后重新hash这个overflow的bucket即可
参考自1
https://www.geeksforgeeks.org/extendible-hashing-dynamic-approach-to-dbms/ ↩︎