可扩展哈希是一种动态哈希方法,其中目录和存储桶用于哈希数据。这是一种非常灵活的方法,其中哈希函数也经历动态变化。
可扩展哈希的主要特征:这种哈希技术的主要特征是:
- 目录:目录在指针中存储存储桶的地址。将一个ID分配给每个目录,该目录可能会在每次目录扩展时发生更改。
- 存储桶:存储桶用于对实际数据进行哈希处理。
可扩展哈希的基本结构:
可扩展哈希中的常用术语:
- 目录:这些容器存储指向存储桶的指针。每个目录都有一个唯一的ID,该ID在每次扩展时都会更改。哈希函数返回此目录ID,该目录ID用于导航到相应的存储桶。目录数= 2 ^全球深度。
- 存储桶:存储散列密钥。目录指向存储桶。如果存储桶的局部深度小于全局深度,则该存储桶可能包含多个指向它的指针。
- 全局深度:它与目录相关联。它们表示哈希函数用来对密钥进行分类的位数。全局深度=目录ID中的位数。
- Local Depth:与Local Depth相同,除了Local Depth与存储桶(而不是目录)相关联这一事实。根据全局深度的局部深度用于确定在发生溢出的情况下要执行的操作。局部深度始终小于或等于全局深度。
- 存储桶拆分:当存储桶中的元素数量超过特定大小时,该存储桶将分为两部分。
- 目录扩展:当存储桶溢出时,将进行目录扩展。当溢出存储桶的本地深度等于全局深度时,将执行目录扩展。
可扩展哈希的基本工作:
- 步骤1 –分析数据元素:数据元素可能以各种形式存在,例如整数,字符串,浮点数等。当前,让我们考虑整数类型的数据元素。例如:49。
- 步骤2 –转换为二进制格式:将数据元素转换为二进制格式。对于字符串元素,请考虑起始字符的ASCII等效整数,然后将其转换为二进制形式。由于我们有49个数据元素,因此其二进制格式为110001。
- 步骤3 –检查目录的全局深度。假设哈希目录的全局深度为3。
- 步骤4 –识别目录:考虑二进制数中LSB的“全球深度”数,并将其与目录ID匹配。
例如。得到的二进制文件:110001和全球深度为3。因此,哈希函数会返回110 001即3个LSB。 001。 - 第5步–导航:现在,导航到目录ID为001的目录所指向的存储桶。
- 步骤6 –插入和溢出检查:插入元素并检查存储桶是否溢出。如果遇到溢出,请执行步骤7,然后执行步骤8 ,否则,请执行步骤9 。
- 步骤7 –在数据插入过程中解决流状况:很多时候,将数据插入存储桶时,可能会发生存储桶溢出的情况。在这种情况下,我们需要遵循适当的程序以避免数据处理不当。
首先,检查局部深度是否小于或等于整体深度。然后选择以下情况之一。- 情况1:如果溢出的存储桶的局部深度等于全局深度,则需要执行目录扩展以及存储桶拆分。然后将全局深度和局部深度值加1。然后,分配适当的指针。
目录扩展将使哈希结构中存在的目录数量增加一倍。 - 情况2:如果局部深度小于整体深度,则仅发生“桶分割”。然后仅将本地深度值加1。然后,分配适当的指针。
- 情况1:如果溢出的存储桶的局部深度等于全局深度,则需要执行目录扩展以及存储桶拆分。然后将全局深度和局部深度值加1。然后,分配适当的指针。
- 第8步-重新分割拆分存储区元素:拆分后的溢出存储区中存在的元素将通过目录的新全局深度进行重新整理。
- 步骤9 –元素成功散列。
基于可扩展散列的示例:现在,让我们考虑对以下元素进行散列的显着示例: 16,4,6,22,24,10,31,7,9,20,26。
铲斗尺寸: 3(假设)
哈希函数:假设全局深度为X。则哈希函数返回X个LSB。
- 解决方案:首先,计算每个给定数字的二进制形式。
16- 10000
4- 00100
6- 00110
22-10110
24- 11000
10-01010
31-11111
7- 00111
9- 01001
20至10100
26- 11010 - 最初,global-depth和local-depth始终为1。因此,哈希帧如下所示:
- 插入16:
16的二进制格式是10000,全局深度是1。哈希函数返回1 LSB of 1000 0 ,即0。因此,16映射到id = 0的目录。
- 插入4和6:
4(10 0 )和6(11 0 )的LSB都为0。因此,它们散列如下:
- 插入22:22的二进制形式是1011 0 。它的LSB为0。目录0指向的存储桶已满。因此,发生溢出。
- 按照步骤7-情况1的指示,由于“本地深度=全局深度”,存储桶将拆分并进行目录扩展。同样,在拆分之后,将对溢出的存储桶中存在的数字进行重新哈希处理。并且,由于全局深度现在增加1,因此全局深度为2。因此,现在将重整16个,4、6、22和2个LSB。[16(100 00 ),4(1 00 ),6( 1 10 ),22(101 10 )]
*Notice that the bucket which was underflow has remained untouched. But, since the number of directories has doubled, we now have 2 directories 01 and 11 pointing to the same bucket. This is because the local-depth of the bucket has remained 1. And, any bucket having a local depth less than the global depth is pointed-to by more than one directories.
- 插入24和10:可以基于ID为00和10的目录对24(110 00 )和10(10 10 )进行哈希处理。在这里,我们不会遇到溢出情况。
- 插入31,7,9:所有这些元素[31(111 11 ),7(1 11 ),9(10 01 )]的LSB均为01或11。因此,它们映射到01和11所指向的存储区上。在这里,我们不会遇到任何溢出情况。
- 插入20:插入数据元素20(101 00 )将再次导致溢出问题。
- 将20插入到由00指出的存储桶中。如步骤7-情况1所示,由于存储桶的本地深度=全局深度,因此目录扩展(加倍)与存储桶拆分一起发生。溢出的存储桶中存在的元素将使用新的全局深度进行重新填充。现在,新的哈希表如下所示:
- 插入26:全局深度为3。因此,考虑了26(11 010 )的3个LSB。因此,26最适合目录010指出的存储桶。
- 存储桶溢出,并且按照步骤7-情况2的指示,由于存储桶的本地深度<全局深度(2 <3) ,目录没有加倍,但是仅存储桶被拆分,元素被重新哈希。
最后,获得散列给定数字列表的输出。
- 这样就完成了11个数字的哈希运算。
关键观察:
- 如果存储桶的局部深度小于全局深度,则将有多个指针指向该存储桶。
- 当存储区中发生溢出情况时,存储区中的所有条目都将以新的本地深度进行重新混合。
- 如果溢出桶的本地深度
- 数据插入过程开始后,无法更改存储桶的大小。
好处:
- 数据检索便宜(就计算而言)。
- 由于存储容量是动态增加的,因此不会出现数据丢失的问题。
- 随着哈希函数的动态变化,关联的旧值被新的哈希函数哈希。
可扩展散列的局限性:
- 如果将多个记录散列在同一目录上,同时又使记录分布不均匀,则目录大小可能会大大增加。
- 每个铲斗的尺寸是固定的。
- 当全局深度和局部深度之差变得过大时,指针将浪费内存。
- 此方法的编码很复杂。
用于实现的数据结构:
- B +树
- 大批
- 链表