除了使用链表的方法,更多的是用开放寻址法
-
线性寻址
(LH(k,0)=H(k))确定了整个探查序列,只有m种不同的探查序列
-
二次寻址
(QH(k,i)={H(k)+c_1*i+c_2*i^2} pmod m),其中(c_1)、(c_2)是两个不为0的常数。若取(c_1=c_2=1),二次探查的散列函数为:
private int QH(int value, int i) { return (H(value) + i + i * i) % 10; }
对于数值 7,(QH())给出的探查序列是 7、9、3、9……由于初始位置(QH(k, 0) = H(k))确定了整个探查序列,所以二次探查同样只有 m 种不同的探查序列。通过让下一个探查位置以 i 的平方偏移,不容易像线性探查那样让被占用的槽连成一片。
-
双重寻址
(H(k,i)={H_1(k)+i*H_2(k)} pmod m)
其中:
(H_1(k)=k pmod m)
(H_2(k)=1+{k pmod {m-1}})
int H1(int value) { return value % _values.Length; } int H2(int value) { return 1 + (value % (_values.Length - 1)); } int DH(int value, int i) { return (H1(value) + i * H2(value)) % _values.Length; } public void Add(int item) { int i = 0; // 已经探查过的槽的数量 do { int j = DH(item, i); // 想要探查的地址 if (_values[j] == null || (int)_values[j] == DELETED) { _values[j] = item; return; } else { i += 1; } } while (i <= _values.Length); throw new Exception("集合溢出"); } public bool Contains(int item) { int i = 0; // 已经探查过的槽的数量 int j = 0; // 想要探查的地址 do { j = DH(item, i); if (_values[j] == null) return false; if ((int)_values[j] == item) return true; else i += 1; } while (i <= _values.Length); return false; } public void Remove(int item) { int i = 0; // 已经探查过的槽的数量 int j = 0; // 想要探查的地址 do { j = DH(item, i); if (_values[j] == null) return; if ((int)_values[j] == item) { _values[j] = DELETED; return; } else { i += 1; } } while (i <= _values.Length); }
总结
此算法(双重探查)在C#中实现,但是在Java的Hashtable源码中,是以单向链表的方式实现hashtable(哈希表)的。