再散列 主要解决对于使用平方探测的开放定址法,表的元素填的太满从而导致操作的运行时间过长 的问题。主要思路就是建立一个两倍大的表,并将元素新散列到第二个表中。
在事前可能会好奇:为什么不直接根据对于数据的估计创建一个相对大的散列表,而要用到再散列的方法。
我的想法是:
1、使用散列表时,数据往往十分多,此时创建一个大的散列表不但不会显著提高运行时间,同时还会浪费大量的空间,这是没有意义的。
2、为了安全保证,我们并不能判断估计是否正确,因此我们必须保证有使其发生问题时提供有解决方案。
现在我们考虑如何进行再散列的时间:1、表装填在一半便进行再散列。2、当插入失败时再散列。3、当表到达某一个装填因子时再散列。方法一是当λ=1/2时的方法三的特殊情况。
下面给出实现。
HashTable ReHash(HashTable H)
{
int i, OldSize;
Cell* OldCells;
OldCells = H->TheCells;
OldSize = H->TableSize;
H = InitializeTable(OldSize * 2);
for (i = 0; i < OldSize; i++)
if (OldCells[i].Info == Legitimate)
Insert(OldCells[i].Element, H);
free(OldCells);
return H;
}
应当注意的是:HashTable H是一个指向结构体的指针,而为其的初始化就是为其中 int 类型的 TableSize 以及 指针类型的Cell *
以及Cell *指向的所有结构体单元分配空间。而再散列的过程中使用的第二个表与第一个表是相同的,初始化就相当于重置了该表了。因此在事前我们用OldCells和OldSize获得了前一个表的数据。
下面介绍可扩散列(extendible hashing)。
该论题处理数据量太大而导致装不进主存(即通常说的运行内存)的情况。它允许两次磁盘访问只执行一次 Find 操作。
可扩散列和二叉树中的B树有着相似的实现方式。
先假设数据由几个6位整数组成。(对于字符串关键字类似)那么我们可以通过寻找一部分的数据前几个数的相同点从而将该部分数据存放在目录为其共同点的根下。并在数据达到一定的规模对数据前几位的位数进行更精确的寻找。即将目录分裂。
其实这种方法可以完全看书的(P132.图5-23到图5-25可以直接看懂),用文字解释反而更为复杂。