数据结构笔记(六)——散列(Hash Table)之双散列和再散列(4)

虽然平方探测排除了一次聚集,但散列到同一位置的元素仍然会探测相同的备选位置,比如当冲突函数为i^2时,对于每个要插入的X,其向前探测地步长都是0,1,4,9,16,这样对于散列到同一位置的X,他们都会探测相同的备选位置,这是二次聚集。双散列对平方探测法里面的冲突函数做了进一步的改进,F(i)进一步的复杂化,引入了另外一个函数hash_2(X),这个函数对每个X都会计算出一个值,而不是和二次函数一样探测同样的位置。比较常见的是F(i)=i*hash_2(X)作为冲突函数,即散列函数为h_i(X)=hash_1(X)+i*hash_2(X)hash_2(X)的选择也十分重要,显然,函数结果一定不能为0.与hash_1(X)类似,hash_2(X)也可以是求余的形式,如hash_2(X)=R - (X mod R)。如下面的例子

数据结构笔记(六)——散列(Hash Table)之双散列和再散列(4)_第1张图片

                         hash_1(X)=X mod 9,hash_2(X)=7 -(X mod 7)  

双散列如果实现得较好,其预期的探测次数几乎和随机冲突解决方法的进行相同。相对于平方探测,它多加了一个散列函数,而平方探测不需要第二个散列函数,因此在实践中更加简单,同时速度更快。但是平方探测法最好表中元素不要填的太满,应该将其装填因子保持在0.5以下。对于元素过满的表,我们可以再散列(rehashing),建立另外一个大约两倍大的表(并且使用一个相关的新的散列函数),扫描整个原始表的元素,通过新的散列函数将原表中未删除的元素散列到新表中。一个例子就是将大小为7的原表中的4个元素(装填因子为0.71)再散列到大小为17的新表中,原散列函数为X mod 7,新的散列函数为X mod 17.

数据结构笔记(六)——散列(Hash Table)之双散列和再散列(4)_第2张图片  数据结构笔记(六)——散列(Hash Table)之双散列和再散列(4)_第3张图片

                    hash(X)=X mod 7                                      hash(X)=X mod 17

再散列代价十分昂贵,运行时间为O(N),如果在交互系统中运用,若有用户刚好插入引起了再散列,他将会感到系统速度变慢。对于再散列的时机,一种是表满到一半就再散列,一种是插入失败才再散列,还有就是达到某个装填因子时再散列。似乎第三种是比较合适的时机,因为装填因子确实对散列的性能有比较大的影响。

再散列在平方探测法中的实现:

HashTb rehashing(HashTb ht)
{
	int old_size = ht->table_size;
	Cell* old_table = ht->table;
	ht = initialize(2 * old_size);
	for (int i = 0; i < old_size; ++i)
	{
		if (old_table[i].info == Legitimate)
		{
			insert(ht, old_table[i].element);
		}
	}
	free(old_table);
	return ht;
}

     

你可能感兴趣的:(数据结构)