Java中哈希表(Hashtable)是如何實現的
Hashtable中有一個內部類Entry,用來保存單元數據,我們用來構建哈希表的每一個數據是Entry的一個實例。假設我們保存下面一組數據,第一列作為key, 第二列作為value。
{“one", 1}
{"two", 2}
{"three", 3}
{"four", 4}
寫一個演示程序:
import java.util.Hashtable;
public class Main {
public static void main(String[] args) {
Hashtable<String, Integer> numbers = new Hashtable<String, Integer>();
numbers.put("one", 1);
numbers.put("two", 2);
numbers.put("three", 3);
numbers.put("four", 4);
numbers.put("five", 5);
Integer n = numbers.get("two");
Integer nn = numbers.get("six");
if(n != null)
System.out.println(n);
System.out.println(nn);
}
}
Hashtable內部用一個Entry數組table,來保存所有的數據。
當我們插入一個新的Entry對象時,即用Hashtable的put(key, value)方法。
在put方法里:
計算key的hash值
計算index值,作為數組table的下標,即table[index]
哈希表中根據key的索引值index,創建了多個bucket,所有index值一樣的Entry對象,構造成一個鏈接表存放在同一個bucket里。既然是一個鏈接表,根據數據結構知識,自然我們的Entry對象需要有一個指向下一個對象的指針,即Entry對象需要有這些屬性:key,value,next。
如何構造hash函數?
hash值,如何生成?對於每個對象的hash值,要保證每一個hash值都不一樣。
在Java SDK中, String的hashCode方法如下:
//hash的初始值為0
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
index值,如何生成?這里要求保存的數據是均勻的分配在每一個bucket中,Hashtable源碼中采用%操作(mod)使數據分布在編號為0~10的bucket中。
Hashtable中put方法的源碼如下:
private int hash(Object k) {
// hashSeed will be zero if alternative hashing is disabled.
return hashSeed ^ k.hashCode();
}
public synchronized V put(K key, V value) {
... ...
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
... ...
}
這樣數據存儲到哈希表之后,當我們要查找或者說獲取一個對象時候,采用同樣的方式可以快速的找到我們需要的對象。
哈希表可以快速的找到一個元素。在有大量的數據的時候,比普通的順序查找要快的多。
假設有10000條數據,如果采用順序查找,最壞的情況下需要對比10000次能找到,最好的情況是1次。平均查找次數位(10000+1)/2,大約為5000次。
換一種方式,如果把10000條數據通過hash值索引分成10組,每一組有1000條數據,這樣每一次只需要先確定是哪一組,然后在1000條數據里查找,這樣最壞的情況是1000次, 最好的情況是1次。平均查找次數為(1000+1)/2 ,大約為500次。比上面的方法快了5倍。
我們常用的5種算法有順序查找,二分法查找,二叉排序樹查找,哈希表法查找,分塊查找。Java的Hashtable即是用了哈希表法查找。
