先创建一个泛型类:
class HashBuck<K,V>{
//K是关键字,V是值
}
定义一个哈希桶的底层节点:
class HashBuck<K,V>{
public static class Node<K,V>{
K key;
V val;
Node<K,V> next;
public Node(K key,V val){//构造方法
this.key=key;
this.val=val;
}
}
double LoadFactor=0.75;//负载因子,大小可以自己决定,不能太大
int useSize;//当前哈希表容量,默认是0
public Node<K,V>[] array=(Node<K,V>[])new Node[10];//用array来管理哈希表,默认长度是10
public void put(K key,V val){//要实现的方法
}
public V get(K key){//要实现的方法
}
}
然后就是实现两个重要方法
public void put(K key,V val){ } 和 public V get(K key){ }
先从get方法开始:
public V get(K key){
int hash=key.hashCode();//调用key自己的hashCode(),获得hash
int index=hash% array.length;//通过哈希函数,得到哈希地址
Node<K,V> cur=array[index];
while(cur!=null){
if(cur.key.equals(key)){//通过key自己的equals方法,判断关键字是否一致,一致返回val
return cur.val;
}
cur=cur.next;
}
return null;//遍历完都没有发现,返回空
}
注意:代码中key调用了equals()和hashCode()方法。
所以,key关键字,如果是自定义类型,一定要重写equals()和hashCode()方法。
put()方法:
public void put(K key, V val) {
int hash = key.hashCode();//得到关键码
int index = hash % array.length;//获取哈希地址
Node<K,V> cur=array[index];
//判断是否有相同的key,有就改正val然后返回
while(cur!=null){
if(cur.key.equals(key)){//改val,然后返回
cur.val=val;
return;
}
cur=cur.next;
}
//程序到这里,说明要么,没有哈希冲突,要么没有一样的key,直接创建节点,然后头插
Node<K,V> newNode=new Node<>(key,val);
newNode.next=array[index];
array[index]=newNode;
useSize++;
if(useSize*1.0/array.length>=LoadFactor){//大于等于负载因子,扩容
reSize();//我把扩容封装成一个方法
}
}
reSize()方法:
private void reSize(){
//创建一个比array大一倍的数组
Node<K,V>[] newArr=(Node<K,V>[])new Node[array.length*2];
for (int i = 0; i <array.length ; i++) {//遍历原来的哈希表
Node<K,V> cur=array[i];
while(cur!=null){
int hash=cur.key.hashCode();
int index=hash%newArr.length;//重新哈希
//头插
Node<K,V> tmp=cur.next;//保存好下一个节点,等一下继续while遍历
cur.next=newArr[index];
newArr[index]=cur;
cur=tmp;
}
}
array=newArr;//把新的哈希表,给到array管理
}
在实际的底层中,如果链表的长度达到一定时,会把他们变成红黑树,比较的复杂,这里就不展示了。