hash算法也叫做散列函數,通過一個函數將任何信息轉換成信息量的摘要。一個設計的比較好的hash算法,其衝突是比較少,衝突的含義就是不同的輸入經過hash後得到了相同的摘要信息。
這裏我分析了一下java源代碼中HashMap的實現。
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
這裏可以針對任何類型的對象進行hash計算,之所以傳入的是int類型,那是因爲java object類中hashcode()方法。該方法的定義也比較有意思。
public native int hashCode(); 說明該方法是c++實現的。因此肯定要加載對應的dll文件。但是這裏並沒有發現加載什麼dll文件。看看java代碼裏面的加載吧。
private static native void registerNatives();
static {
registerNatives();
}
我看到這裏後,徹底暈倒了。我僅能得到的結論是:hashmap的實現中,java是將key值進行hashcode計算得到int類型,然後再hash計算得到摘要信息。看看hashmap的put方法吧。
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
這裏首先調用了hash(key.hashCode())對key值進行hash,得出的值到table中查詢,table是存放所有的值的數組,該數組的包含的對象是Entry對象,這個對象就像鏈表裏面的節點一樣。具體可以看看代碼了。然後對其hash值進行查找,並看table中該索引下的值是否爲空,如果不爲空的話,則在當前位置的元素中,建立一個鏈接,新建一個Entry對象,這樣,在table數組當前的索引下,就是一個鏈表了。這是處理衝突的一種方法。如果table中該索引下的值是空的,說明使用正常,不存在衝突。
需要注意下哦,這裏hash出來的值比較大,但是如何把這麼大的值直接映射到這麼小的數組空間上來呢,在indexFor()方法裏面有一些眉目可以看到
static int indexFor(int h, int length) {
return h & (length-1);
}
經過與計算後,再大的值都會在數組空間範圍內了。
關於java裏面的hash就記錄到這裏了。
以下有一篇翻譯的文章對理解hash比較有幫助。而且記錄有各種hash算法。摘錄以下代碼記錄一下。
http://blog.csdn.net/eaglex/article/details/6310727
package com.bplead.hash;
public class Hash {
public static long RSHash(String str){
int b = 378551;
int a = 63689;
long hash = 0;
for(int i=0;i<str.length();i++){
hash = hash * a + str.charAt(i);
a = a +b;
}
return hash;
}
public static long JSHash(String str){
long hash = 1315423911;
for(int i = 0; i < str.length(); i++)
{
hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
}
return hash;
}
public long SDBMHash(String str){
long hash = 0;
for(int i = 0; i < str.length(); i++)
{
hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;
}
return hash;
}
public long DJBHash(String str){
long hash = 5381;
for(int i = 0; i < str.length(); i++)
{
hash = ((hash << 5) + hash) + str.charAt(i);
}
return hash;
}
public long DEKHash(String str){
long hash = str.length();
for(int i = 0; i < str.length(); i++)
{
hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
}
return hash;
}
public static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
public static void main(String[] args) {
String temp = "HelloWorld12";
int index = hash(temp.hashCode());
System.out.println(index);
System.out.println(index&15);
}
}