常见hash算法

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效果最差,但得分类似,其算法本质是类似的。 

数组

#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); } 
相关文章
相关标签/搜索