由TreeMap实现的哈希表。由于TreeMap中K需要有可比较性,所以哈希表中的K要有可比较性。若采用链表实现哈希表,则不需要K有可比较性。
public class HashTable<K extends Comparable<K>,V> {
//TreeMap数组,用于存放每一个tree
private TreeMap<K, V>[] table;
//质数,table的空间
private int prime;
//table中元素个数
private int size;
//哈希冲突的最大容忍度
private static final int upperTol=10;
//哈希冲突的最小容忍度
private static final int lowerTol=2;
//质数数组,table数组默认的空间
private int [] initCapcity={31,53,97,193,389,769,1543,3079,6151,
12289,24593,49157,98317,196613,393241,786433,1572869,
3145739,6291469,12582917,25165843,50331653,100663319,
201326611,402653189,805306457,1610612741};
//initCapcity数组的下标
private int index;
//构造函数
public HashTable() {
index=0;
this.prime=initCapcity[index];
//开辟prime个空间,每个空间初始化一棵树
table=new TreeMap[prime];
for(int i=0;i<prime;i++) {
table[i]=new TreeMap<>();
}
size=0;
}
//计算散列码
private int hash(K key) {
return Math.abs(key.hashCode())%prime;
}
public int getSize() {
return size;
}
//添加元素
public void add(K key,V value) {
int hash=hash(key);
if(table[hash].containsKey(key)) {
table[hash].put(key, value);
}else{
table[hash].put(key, value);
size++;
//扩容:当元素的个数比哈希冲突最大容忍度与空间个数的乘积还要大,且数组下标不会越界,扩容
if(size>upperTol*prime&&index+1<initCapcity.length)
resize(initCapcity[++index]);
}
}
//删除元素
public V remove(K key) {
int hash=hash(key);
V val=null;
if(table[hash].containsKey(key)) {
val=table[hash].remove(key);
size--;
}
//缩容
if(size<lowerTol*initCapcity[index]&&index>0)
resize(initCapcity[--index]);
return val;
}
//更新元素
public void set(K key,V val) {
TreeMap cur=table[hash(key)];
if(!cur.containsKey(key))
throw new IllegalArgumentException("");
cur.put(key, val);
}
//查找K对应的V
public V get(K key) {
return table[hash(key)].get(key);
}
//是否包含K
public boolean contains(K key) {
return table[hash(key)].containsKey(key);
}
//改变容量
private void resize(int newPrime) {
//开辟新的空间
TreeMap<K,V>[] newTable=new TreeMap[newPrime];
for(int i=0;i<newPrime;i++)
newTable[i]=new TreeMap<>();
this.prime=newPrime;
//新旧table内容传递
for(TreeMap<K,V> tab:table) {
for(K key:tab.keySet())
newTable[hash(key)].put(key,tab.get(key));
}
this.table=newTable;
}
@Override
public String toString() {
// TODO 自动生成的方法存根
StringBuilder strBd=new StringBuilder();
for(int i=0;i<table.length;i++) {
strBd.append("HashTable["+i+"]—>"+table[i].toString()+"\n");
}
return strBd.toString();
}
}
一个简单的测试类,对table添加5000次任意的数,Value代表每个数出现的频率。
public class Test {
public static void main(String [] args) {
HashTable<Integer, Integer> table=new HashTable<>();
Random random=new Random();
for(int i=0;i<5000;i++) {
int ran=random.nextInt(100000);
if(table.contains(ran))
table.set(ran, table.get(ran)+1);
else
table.add(ran, 1);
}
System.out.println(table);
}
}
运行后部分结果如图所示: