红黑树实现过于复杂,当不需要符号表中的键值有序时可以使用哈希表来实现符号表
哈希表同红黑树一样高效,但是实现简单
哈希表使用数组存储键值对,通过一个hash函数把key转成数组的索引,然后把value存储在数组中该索引的位置
如果不同的key通过hash函数转换的索引i相同,则把i位置的不同key-value值通过链表链接起来
查找的时候先通过hash找到索引位置,再遍历链表找到与key相同的key-value值
public class SeparateChainingHashST<Key, Value> {
private static final int INIT_CAPACITY = 4;
private int n; // number of key-value pairs
private int m; // hash table size
private SequentialSearchST<Key, Value>[] st; // array of linked-list symbol tables
/**
* Initializes an empty symbol table.
*/
public SeparateChainingHashST() {
this(INIT_CAPACITY);
}
/**
* Initializes an empty symbol table with {@code m} chains.
* @param m the initial number of chains
*/
public SeparateChainingHashST(int m) {
this.m = m;
st = (SequentialSearchST<Key, Value>[])new SequentialSearchST[m];
for(int i = 0; i < m; i++) {
st[i] = new SequentialSearchST<Key, Value>();
}
}
// resize the hash table to have the given number of chains,
// rehashing all of the keys
private void resize(int chains) {
SeparateChainingHashST<Key, Value> temp = new SeparateChainingHashST<Key, Value>(chains);
for (int i = 0; i < m; i++) {
for (Key key : st[i].keys()) {
temp.put(key, st[i].get(key));
}
}
this.m = temp.m;
this.n = temp.n;
this.st = temp.st;
}
// hash value between 0 and m-1
//hash函数一般实现是把key转换成32为无符号整数,然后与数组长度m取余就可以得到一个0到m-1的索引值
//hash函数的设计很重要,不均匀的hash值会导致同一索引位置的链表很长,查询就比较慢了
//java为基本的Integer,Long,Double,String都实现了hash函数hashcode, 查找时先根据key的hashCode找到数组索引,
//然后遍历链表通过equal()判断key是否相同
//我们在设计自定义类型的hashCode函数时可以参考java库里面的实现,比如把每个成员的hashCode相加
private int hash(Key key) {
return (key.hashCode() & 0x7fffffff) % m;
}
/**
* Returns the number of key-value pairs in this symbol table.
*
* @return the number of key-value pairs in this symbol table
*/
public int size() {
return n;
}
/**
* Returns true if this symbol table is empty.
*
* @return {@code true} if this symbol table is empty;
* {@code false} otherwise
*/
public boolean isEmpty() {
return size() == 0;
}
/**
* Returns true if this symbol table contains the specified key.
*
* @param key the key
* @return {@code true} if this symbol table contains {@code key};
* {@code false} otherwise
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
public boolean contains(Key key) {
if (key == null) throw new IllegalArgumentException("argument to contains() is null");
return get(key) != null;
}
/**
* Returns the value associated with the specified key in this symbol table.
*
* @param key the key
* @return the value associated with {@code key} in the symbol table;
* {@code null} if no such value
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
public Value get(Key key) {
if