在Java
中,有一種而且我們使用很頻繁的資料結構,叫做HashMap
,其實準確的來說,這是雜湊表
的一種衝突解決的實現,那麼什麼是雜湊表
呢?這個概念在網上可以找到很多專業的回答,這裡我們就舉一個很簡單的例子來說明一下什麼是雜湊表
。
首先我們要明確的一點,就是雜湊表肯定是用來存取東西的,那麼如果我們要把西瓜
,蘋果
,草莓
這三種東西按照重量
存到某個地方,方便我們後面再拿來使用,這個該如何操作呢?首先我們可以拿一個彈簧,然後使用這個彈簧將這些東西按照重量彈出去,因為重量的不同,將會落在不同的區域,這樣就將這些東西“儲存”了起來。如果我們後面要使用這些東西的時候,只需要按照重量再去使用一次彈簧就可以了,這樣就能找到我們所需要找的。
這裡我們再明確幾個概念,這個例子中的幾種東西,就是我們要存放的資料
,彈簧指的是hash演算法
,因為這些資料的存放是無序的,所以這些概念綜合起來看,稱這種形式為雜湊表
。
還有一個問題,就是如果在這個雜湊表中有兩個資料通過hash
演算法落到了同一個區域,那麼在這裡就稱之為衝突
,或者叫hash
衝突,在雜湊表中,解決衝突的方式有線性探測法
,平方探測法
,鏈式地址法
。。。很多種方式,在這裡就不討論每一種解決方式的利弊,我們只是對於Java
中的HashMap
作為研究。
如果看過HashMap
原始碼的朋友就會知道,在Java
中HashMap
是基於鏈式地址法來實現的,當然也有很多朋友可能不太喜歡看原始碼,好的,那麼我們就按照HashMap
來動手寫一個簡單的實現。
我們先定義一個節點類。
public class Entry {
private Integer key;
private String value;
private Entry next;
public Entry(Integer key, String value, Entry next){
this.key = key;
this.value = value;
this.next = next;
}
}
然後我們在定義一個CopyHashMap類。
public class CopyHashMap {
private final static int DEFAULT_CAPCITY = 11;
private Entry[] arrEntry;
public CopyHashMap(){
arrEntry = new Entry[DEFAULT_CAPCITY];
}
public CopyHashMap(int size){
arrEntry = new Entry[size];
}
private int hash(int key){
return key % DEFAULT_CAPCITY;
}
public String get(int key){
int h = hash(key);
Entry entry = arrEntry[h];
for (Entry e = entry; e != null; e = e.getNext()){
if (e.getKey().equals(key)){
return e.getValue();
}
}
return null;
}
public void put(int key, String value){
int h = hash(key);
Entry entry = arrEntry[h];
for (Entry e = entry; e != null; e = e.getNext()){
if (e.getKey().equals(key)){
e.setValue(value);
}
}
arrEntry[h] = new Entry(key, value, arrEntry[h]);
}
}
這裡只是簡單的寫了一個get
和put
方法,程式碼很簡單,看一看應該都能明白,可以看到其底層實現還是依賴於一個陣列,這裡有一個hash
的方法,這個就是我們剛開始例子中的彈簧,對於每一個key
都要去計算對應的hash
值是多少,然後才能確定存放在陣列中的哪個位置,所以能夠看出,雜湊表
中的hash
演算法的設計是非常重要的。
這段程式碼中還有一些東西沒有做,比如remove
方法,還有rehash
方法,如果你有興趣,那麼可以動手實現一下這兩個方法,rehash
的過程在這裡順便提一下,簡單的說就是如果儲存列表不夠用的情況下,hash
表會擴容,然後將裡面的資料重新hash
一次,當然這個rehash
會提前開始進行的,所以這裡我們可以觀察到一個現象就是如果雜湊表rehash
一次,對程式的效能影響還是比較大的,對了,在JDK8
中,HashMap
也做了一些改進,鏈式儲存的時候,在其長度達到某一個定值,後面的儲存方式會轉為紅黑樹的形式,有興趣的話可以看一下原始碼。
HashMap
在Java
中的使用很頻繁,很多人應該都懂其原理,可能也有很多人不太明白,希望這篇文章能讓大家初窺HashMap
的門道,更深入的研究就只能大家自己探索了。