hash算法的意義在於提供了一種快速存取數據的方法,它用一種算法創建鍵值與真實值之間的對應關係,(每個真實值只能有一個鍵值,可是一個鍵值能夠對應多個真實值),這樣能夠快速在數組等條件中裏面存取數據.
在網上看了很多HASH資料,因此對HASH的相關資料進行總結和收集。
//HashTable.h template class HashTable{ public : HashTable( int count ) ; void put( T* t ,int key ) ; T* get( int key ) ; private : T** tArray ; }
//HashTable.cpp template HashTable::HashTable( int count ){ tArray = new T*[count] ;} template void HashTable::put( T* t , int key ){ this->tArray[ key ] = t ;}template T* HashTable::get( int key ) { return this->tArray[ key ] ;}
這樣,咱們只要知道key值,就能夠快速存取T類型的數據,而不用像在鏈表等數據結構中查找同樣, 要找來找去的. 至於key值,通常都是用某種算法(所謂的Hash算法)算出來的.例如:字符串的Hash算法, char* value = "hello"; int key = (((((((27* (int)'h'+27)* (int)'e') + 27) * (int)'l') + 27) * (int)'l' +27) * 27 ) + (int)'o' ; Hash函數處理流程Hash,通常翻譯作"散列",也有直接音譯爲"哈希"的,就是把任意長度的輸入(又叫作預映射, pre-image),經過散列算法,變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間一般遠小於輸入的空間,不一樣的輸入可能會散列成相同的輸出,而不可能從散列值來惟一的肯定輸入值。簡單的說就是一種將任意內容的輸入轉換成相同長度輸出的加密方式.
我來作一個比喻吧。
咱們有不少的小豬,每一個的體重都不同,假設體重分佈比較平均(咱們考慮到公斤級別),咱們按照體重來分,劃分紅100個小豬圈。
而後把每一個小豬,按照體重趕進各自的豬圈裏,記錄檔案。
好了,若是咱們要找某個小豬怎麼辦呢?咱們須要每一個豬圈,每一個小豬的比對嗎?
固然不須要了。
咱們先看看要找的這個小豬的體重,而後就找到了對應的豬圈了。
在這個豬圈裏的小豬的數量就相對不多了。
咱們在這個豬圈裏就能夠相對快的找到咱們要找到的那個小豬了。
對應於hash算法。
就是按照hashcode分配不一樣的豬圈,將hashcode相同的豬放到一個豬圈裏。
查找的時候,先找到hashcode對應的豬圈,而後在逐個比較裏面的小豬。
因此問題的關鍵就是建造多少個豬圈比較合適。
若是每一個小豬的體重所有不一樣(考慮到毫克級別),每一個都建一個豬圈,那麼咱們能夠最快速度的找到這頭豬。缺點就是,建造那麼多豬圈的費用有點過高了。
若是咱們按照10公斤級別進行劃分,那麼建造的豬圈只有幾個吧,那麼每一個圈裏的小豬就不少了。咱們雖然能夠很快的找到豬圈,但從這個豬圈裏逐個肯定那頭小豬也是很累的。
因此,好的hashcode,能夠根據實際狀況,根據具體的需求,在時間成本(更多的豬圈,更快的速度)和空間本(更少的豬圈,更低的空間需求)之間平衡。
Hash算法有不少不少種類。具體的能夠參考以前我寫的Hash算法的一些分析。本處給你們提供一個集合了不少使用的Hash算法的類,應該能夠知足很多人的須要的:
Java代碼
經常使用的字符串Hash函數還有ELFHash,APHash等等,都是十分簡單有效的方法。這些函數使用位運算使得每個字符都對最後的函數值產生影響。另外還有以MD5和SHA1爲表明的雜湊函數,這些函數幾乎不可能找到碰撞。
經常使用字符串哈希函數有BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash,PJWHash,ELFHash等等。對於以上幾種哈希函數,我對其進行了一個小小的評測。
Hash函數 數據1 數據2 數據3 數據4 數據1得分 數據2得分 數據3得分 數據4得分 平均分
BKDRHash 2 0 4774 481 96.55 100 90.95 82.05 92.64
APHash 2 3 4754 493 96.55 88.46 100 51.28 86.28
DJBHash 2 2 4975 474 96.55 92.31 0 100 83.43
JSHash 1 4 4761 506 100 84.62 96.83 17.95 81.94
RSHash 1 0 4861 505 100 100 51.58 20.51 75.96
SDBMHash 3 2 4849 504 93.1 92.31 57.01 23.08 72.41
PJWHash 30 26 4878 513 0 0 43.89 0 21.95
ELFHash 30 26 4878 513 0 0 43.89 0 21.95
其中數據1爲100000個字母和數字組成的隨機串哈希衝突個數。數據2爲100000個有意義的英文句子哈希衝突個數。數據3爲數據1的哈希值與1000003(大素數)求模後存儲到線性表中衝突的個數。數據4爲數據1的哈希值與10000019(更大素數)求模後存儲到線性表中衝突的個數。
通過比較,得出以上平均得分。平均數爲平方平均數。能夠發現,BKDRHash不管是在實際效果仍是編碼實現中,效果都是最突出的。APHash也是較爲優秀的算法。DJBHash,JSHash,RSHash與SDBMHash各有千秋。PJWHash與ELFHash效果最差,但得分類似,其算法本質是類似的。
在信息修競賽中,要本着易於編碼調試的原則,我的認爲BKDRHash是最適合記憶和使用的
C++實現
#define M 249997
#define M1 1000001
#define M2 0xF0000000
// RS Hash Function
unsigned int RSHash(char*str)
{
unsigned int b=378551 ;
unsigned int a=63689 ;
unsigned int hash=0 ;
while(*str)
{
hash=hash*a+(*str++);
a*=b ;
}
return(hash % M);
}
// JS Hash Function
unsigned int JSHash(char*str)
{
unsigned int hash=1315423911 ;
while(*str)
{
hash^=((hash<<5)+(*str++)+(hash>>2));
}
return(hash % M);
}
// P. J. Weinberger Hash Function
unsigned int PJWHash(char*str)
{
unsigned int BitsInUnignedInt=(unsigned int)(sizeof(unsigned int)*8);
unsigned int ThreeQuarters=(unsigned int)((BitsInUnignedInt*3)/4);
unsigned int OneEighth=(unsigned int)(BitsInUnignedInt/8);
unsigned int HighBits=(unsigned int)(0xFFFFFFFF)<<(BitsInUnignedInt-OneEighth);
unsigned int hash=0 ;
unsigned int test=0 ;
while(*str)
{
hash=(hash<<OneEighth)+(*str++);
if((test=hash&HighBits)!=0)
{
hash=((hash^(test>>ThreeQuarters))&(~HighBits));
}
}
return(hash % M);
}
// ELF Hash Function
unsigned int ELFHash(char*str)
{
unsigned int hash=0 ;
unsigned int x=0 ;
while(*str)
{
hash=(hash<<4)+(*str++);
if((x=hash&0xF0000000L)!=0)
{
hash^=(x>>24);
hash&=~x ;
}
}
return(hash % M);
}
// BKDR Hash Function
unsigned int BKDRHash(char*str)
{
unsigned int seed=131 ;// 31 131 1313 13131 131313 etc..
unsigned int hash=0 ;
while(*str)
{
hash=hash*seed+(*str++);
}
return(hash % M);
}
// SDBM Hash Function
unsigned int SDBMHash(char*str)
{
unsigned int hash=0 ;
while(*str)
{
hash=(*str++)+(hash<<6)+(hash<<16)-hash ;
}
return(hash % M);
}
// DJB Hash Function
unsigned int DJBHash(char*str)
{
unsigned int hash=5381 ;
while(*str)
{
hash+=(hash<<5)+(*str++);
}
return(hash % M);
}
// AP Hash Function
unsigned int APHash(char*str)
{
unsigned int hash=0 ;
int i ;
for(i=0;*str;i++)
{
if((i&1)==0)
{
hash^=((hash<<7)^(*str++)^(hash>>3));
}
else
{
hash^=(~((hash<<11)^(*str++)^(hash>>5)));
}
}
return(hash % M);
}
/**
* Hash算法大全<br>
* 推薦使用FNV1算法
* @algorithm None
* @author Goodzzp 2006-11-20
* @lastEdit Goodzzp 2006-11-20
* @editDetail Create
*/
public class HashAlgorithms
{
/**
* 加法hash
* @param key 字符串
* @param prime 一個質數
* @return hash結果
*/
public static int additiveHash(String key, int prime)
{
int hash, i;
for (hash = key.length(), i = 0; i < key.length(); i++)
hash += key.charAt(i);
return (hash % prime);
}
/**
* 旋轉hash
* @param key 輸入字符串
* @param prime 質數
* @return hash值
*/
public static int rotatingHash(String key, int prime)
{
int hash, i;
for (hash=key.length(), i=0; i<key.length(); ++i)
hash = (hash<<4)^(hash>>28)^key.charAt(i);
return (hash % prime);
// return (hash ^ (hash>>10) ^ (hash>>20));
}
// 替代:
// 使用:hash = (hash ^ (hash>>10) ^ (hash>>20)) & mask;
// 替代:hash %= prime;
/**
* MASK值,隨便找一個值,最好是質數
*/
static int M_MASK = 0x8765fed1;
/**
* 一次一個hash
* @param key 輸入字符串
* @return 輸出hash值
*/
public static int oneByOneHash(String key)
{
int hash, i;
for (hash=0, i=0; i<key.length(); ++i)
{
hash += key.charAt(i);
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
// return (hash & M_MASK);
return hash;
}
/**
* Bernstein's hash
* @param key 輸入字節數組
* @param level 初始hash常量
* @return 結果hash
*/
public static int bernstein(String key)
{
int hash = 0;
int i;
for (i=0; i<key.length(); ++i) hash = 33*hash + key.charAt(i);
return hash;
}
//
//// Pearson's Hash
// char pearson(char[]key, ub4 len, char tab[256])
// {
// char hash;
// ub4 i;
// for (hash=len, i=0; i<len; ++i)
// hash=tab[hash^key[i]];
// return (hash);
// }
//// CRC Hashing,計算crc,具體代碼見其餘
// ub4 crc(char *key, ub4 len, ub4 mask, ub4 tab[256])
// {
// ub4 hash, i;
// for (hash=len, i=0; i<len; ++i)
// hash = (hash >> 8) ^ tab[(hash & 0xff) ^ key[i]];
// return (hash & mask);
// }
/**
* Universal Hashing
*/
public static int universal(char[]key, int mask, int[] tab)
{
int hash = key.length, i, len = key.length;
for (i=0; i<(len<<3); i+=8)
{
char k = key[i>>3];
if ((k&0x01) == 0) hash ^= tab[i+0];
if ((k&0x02) == 0) hash ^= tab[i+1];
if ((k&0x04) == 0) hash ^= tab[i+2];
if ((k&0x08) == 0) hash ^= tab[i+3];
if ((k&0x10) == 0) hash ^= tab[i+4];
if ((k&0x20) == 0) hash ^= tab[i+5];
if ((k&0x40) == 0) hash ^= tab[i+6];
if ((k&0x80) == 0) hash ^= tab[i+7];
}
return (hash & mask);
}
/**
* Zobrist Hashing
*/
public static int zobrist( char[] key,int mask, int[][] tab)
{
int hash, i;
for (hash=key.length, i=0; i<key.length; ++i)
hash ^= tab[i][key[i]];
return (hash & mask);
}
// LOOKUP3
// 見Bob Jenkins(3).c文件
// 32位FNV算法
static int M_SHIFT = 0;
/**
* 32位的FNV算法
* @param data 數組
* @return int值
*/
public static int FNVHash(byte[] data)
{
int hash = (int)2166136261L;
for(byte b : data)
hash = (hash * 16777619) ^ b;
if (M_SHIFT == 0)
return hash;
return (hash ^ (hash >> M_SHIFT)) & M_MASK;
}
/**
* 改進的32位FNV算法1
* @param data 數組
* @return int值
*/
public static int FNVHash1(byte[] data)
{
final int p = 16777619;
int hash = (int)2166136261L;
for(byte b:data)
hash = (hash ^ b) * p;
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return hash;
}
/**
* 改進的32位FNV算法1
* @param data 字符串
* @return int值
*/
public static int FNVHash1(String data)
{
final int p = 16777619;
int hash = (int)2166136261L;
for(int i=0;i<data.length();i++)
hash = (hash ^ data.charAt(i)) * p;
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return hash;
}
/**
* Thomas Wang的算法,整數hash
*/
public static int intHash(int key)
{
key += ~(key << 15);
key ^= (key >>> 10);
key += (key << 3);
key ^= (key >>> 6);
key += ~(key << 11);
key ^= (key >>> 16);
return key;
}
/**
* RS算法hash
* @param str 字符串
*/
public static int RSHash(String str)
{
int b = 378551;
int a = 63689;
int hash = 0;
for(int i = 0; i < str.length(); i++)
{
hash = hash * a + str.charAt(i);
a = a * b;
}
return (hash & 0x7FFFFFFF);
}
/* End Of RS Hash Function */
/**
* JS算法
*/
public static int JSHash(String str)
{
int hash = 1315423911;
for(int i = 0; i < str.length(); i++)
{
hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
}
return (hash & 0x7FFFFFFF);
}
/* End Of JS Hash Function */
/**
* PJW算法
*/
public static int PJWHash(String str)
{
int BitsInUnsignedInt = 32;
int ThreeQuarters = (BitsInUnsignedInt * 3) / 4;
int OneEighth = BitsInUnsignedInt / 8;
int HighBits = 0xFFFFFFFF << (BitsInUnsignedInt - OneEighth);
int hash = 0;
int test = 0;
for(int i = 0; i < str.length();i++)
{
hash = (hash << OneEighth) + str.charAt(i);
if((test = hash & HighBits) != 0)
{
hash = (( hash ^ (test >> ThreeQuarters)) & (~HighBits));
}
}
return (hash & 0x7FFFFFFF);
}
/* End Of P. J. Weinberger Hash Function */
/**
* ELF算法
*/
public static int ELFHash(String str)
{
int hash = 0;
int x = 0;
for(int i = 0; i < str.length(); i++)
{
hash = (hash << 4) + str.charAt(i);
if((x = (int)(hash & 0xF0000000L)) != 0)
{
hash ^= (x >> 24);
hash &= ~x;
}
}
return (hash & 0x7FFFFFFF);
}
/* End Of ELF Hash Function */
/**
* BKDR算法
*/
public static int BKDRHash(String str)
{
int seed = 131; // 31 131 1313 13131 131313 etc..
int hash = 0;
for(int i = 0; i < str.length(); i++)
{
hash = (hash * seed) + str.charAt(i);
}
return (hash & 0x7FFFFFFF);
}
/* End Of BKDR Hash Function */
/**
* SDBM算法
*/
public static int SDBMHash(String str)
{
int hash = 0;
for(int i = 0; i < str.length(); i++)
{
hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;
}
return (hash & 0x7FFFFFFF);
}
/* End Of SDBM Hash Function */
/**
* DJB算法
*/
public static int DJBHash(String str)
{
int hash = 5381;
for(int i = 0; i < str.length(); i++)
{
hash = ((hash << 5) + hash) + str.charAt(i);
}
return (hash & 0x7FFFFFFF);
}
/* End Of DJB Hash Function */
/**
* DEK算法
*/
public static int DEKHash(String str)
{
int hash = str.length();
for(int i = 0; i < str.length(); i++)
{
hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
}
return (hash & 0x7FFFFFFF);
}
/* End Of DEK Hash Function */
/**
* AP算法
*/
public static int APHash(String str)
{
int hash = 0;
for(int i = 0; i < str.length(); i++)
{
hash ^= ((i & 1) == 0) ? ( (hash << 7) ^ str.charAt(i) ^ (hash >> 3)) :
(~((hash << 11) ^ str.charAt(i) ^ (hash >> 5)));
}
// return (hash & 0x7FFFFFFF);
return hash;
}
/* End Of AP Hash Function */
/**
* JAVA本身帶的算法
*/
public static int java(String str)
{
int h = 0;
int off = 0;
int len = str.length();
for (int i = 0; i < len; i++)
{
h = 31 * h + str.charAt(off++);
}
return h;
}
/**
* 混合hash算法,輸出64位的值
*/
public static long mixHash(String str)
{
long hash = str.hashCode();
hash <<= 32;
hash |= FNVHash1(str);
return hash;
}