Java集合之Hashtable理论(散列表)
除了使用链表的方法,更多的是用开放寻址法
-
线性寻址
\(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(哈希表)的。