哈希函数BKDR的解析

来源:互联网 发布:怎么下载导航软件 编辑:程序博客网 时间:2024/06/15 10:08

转载于:http://blog.csdn.net/wanglx_/article/details/40400693#comments

作者:wanglx2012

             BKDRHASH是一种字符哈希算法,像BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash,PJWHash,ELFHash等等,这些都是比较经典的,通过http://blog.csdn.net/wanglx_/article/details/40300363(字符串哈希函数)这篇文章,我们可知道,BKDRHash是比较好的一个获取哈希值的方法。下面就讲解这个BKDRHash函数是如何推导实现的。

            当我看到BKDRHash的代码时,不禁就疑惑了,这里面有个常数Seed,取值为31、131等,为什么要这么取,我取其他的值不行吗?还有为什么要将每个字符相加,并乘以这个Seed? 这些到底是什么含义? 最后想了老半天都是不得其解,最后绕进素数里面出不来了……最后在一位牛人的指点下,才茅塞顿开,下面把我的想法和推导过程记录如下。

BKDRHash计算公式的推导

          由一个字符串(比如:ad)得到其哈希值,为了减少碰撞,应该使该字符串中每个字符都参与哈希值计算,使其符合雪崩效应,也就是说即使改变字符串中的一个字节,也会对最终的哈希值造成较大的影响。我们直接想到的办法就是让字符串中的每个字符相加,得到其和SUM,让SUM作为哈希值,如SUM(ad)= a+d;可是根据ascii码表得知a(97)+d(100)=b(98)+c(99),那么发生了碰撞,我们发现直接求和的话会很容易发生碰撞,那么怎么办哪?我们可以对字符间的差距进行放大,乘以一个系数:

SUM(ad) =系数1 * a + 系数2 * d

SUM(bc)= 系数1 * b + 系数2 * c

系数1不等于系数2,这样SUM(ad)等于SUM(bc)的概率就会大大减小。

           可是我们的字符串不可能只有两位或者三位,我们也不可能为每个系数去人为的赋值,但是字符串中有位数的顺序,比如在”ab”中,b是第0位,a是第1位,那么我们可以用系数的n次方作为每个字符的系数,但这个系数不能为1:

SUM(ad) =系数^1 * a + 系数^0 * d

SUM(bc)= 系数^1 * b + 系数^0 * c

这样我们就大大降低了碰撞的发生,下面我们假设有个字符数组p,有n个元素,那么


即:


下面就是这个“系数”取值的问题,取什么值那?从上面的分析来看,取除1之外的什么值都可以,我们知道整数不是奇数就是偶数,为了便于推算我们将偶数分为2的幂的偶数和非2的幂的偶数,也就是分3种取值讨论

系数的推导

现在我们的任务是推导系数的值,分2的幂的偶数、非2的幂的偶数、奇数三个部分讨论。

a.      取2的幂

假如我们取32,也就是2^5,那么我们计算SUM(ad)和SUM(bc)结果如下:

结果不同,有效处理了碰撞。

但是当我们进一步测试会发现,当我们取SUM(ahijklmn)和SUM(hijklmn)时计算得:

取SUM(abhijklmn)和SUM(abchijklmn)时计算得:

SUM(abcdefghijklmn)和SUM(123456hijklmn)时计算得:

我们会发现,只要最末尾的”hijklmn”这几个字符不变,不管前面怎么变,得到的哈希值都是一样的,完全碰撞了!这是为什么那?

          首先哈希值SUM的存储类型用什么?当然用unsignedint ,因为值会很大,unsigned int 是32位,而只要计算就可能会溢出,CPU对于溢出的处理是抛弃最高位,比如两个unsigned int 的值相加结果为33位,那么最高位33位就会被抛弃,那么我们对上面的情况进行计算:

计算SUM(ahijklmn)和SUM(bhijklmn):

SUM(ahijklmn)= 32^7*a + 32^6*h + 32^5*I + 32^4*j + 32^3*k + 32^2*l + 32^1*m + 32^0*n

SUM(bhijklmn)= 32^7*b + 32^6*h + 32^5*I + 32^4*j + 32^3*k + 32^2*l + 32^1*m + 32^0*n

将32换为2^5得:

SUM(ahijklmn)= 2^35*a + 2^30*h + 2^25*I + 2^20*j + 2^15*k + 2^10*l + 2^5*m + 2^0*n

SUM(bhijklmn)= 2^35*b + 2^30*h + 2^25*I + 2^20*j + 2^15*k + 2^10*l + 2^5*m + 2^0*n

由此可知SUM(ahijklmn)和SUM(bhijklmn)都大于unsignedint所能表达的最大值,所以需要抛弃最高位,也就是对0x100000000(也就是2^33)取余,根据同余定理:

(a+b)%m= (a%m + b%m)%m

(a*b)%m= (a%m * b%m)%m

可知

SUM(ahijklmn)%2^33 = (2^35*a% 2^33  +  2^30*h% 2^33  + … +  2^0*n%2^33)% 2^33

SUM(bhijklmn)%2^33 = (2^35*b % 2^33  +  2^30*h % 2^33  + … +  2^0*n%2^33) 2^33

2^35*a% 2^33和 2^35*b % 2^33 为零,所以因溢出被CPU舍弃,得

SUM(ahijklmn)%2^33 = (2^30*h% 2^33  + … +  2^0*n% 2^33) 2^33

SUM(bhijklmn)%2^33 = (2^30*h % 2^33  + … +  2^0*n% 2^33) 2^33

最终他们的哈希值为

SUM(ahijklmn)= 2^30*h + 2^25*I + 2^20*j + 2^15*k + 2^10*l + 2^5*m + 2^0*n

SUM(bhijklmn)= 2^30*h + 2^25*I + 2^20*j + 2^15*k + 2^10*l + 2^5*m + 2^0*n

所以SUM(ahijklmn)等于SUM(bhijklmn),这就是为什么” hijklmn”不变时,不管前面是什么字符串都会被舍弃,得到一样的字符串。这里用的是32=2^5,只要你用2^n,n不管为多少都不行,都会因为字符串的长度达到一定值而造成前面的被舍弃,造成一直碰撞。

b.       取非2的幂的偶数

既然去取2的幂不行,那么我们取非2的幂的偶数,假如我们取6作为系数,6为2^2+2,我们由上面取2的幂的推导可知,当字符的长度大于等于33时,系数就会变为6^32=3*2^33,可知系数大于2^32,对2^33取余,被舍弃,那么造成只要后32个字符不变,前面不管有多少个同的字符,都会被舍弃,计算所得的哈希值也就一样。

由上面两块可知,系数取偶数行不通

c.      取奇数(大于1)

假如我们取9=2^3+1,9^2=81=80+1,9^3=729=728+1,… ,9^n=9^n-1+1,我们知道9的幂肯定是奇数,那么9^n-1肯定为偶数,由上面的推论可知字符串达到一定的长度时,偶数系数前面的字符是可以舍弃的,可是9^n=9^n-1+1,最后的1是永远不会被舍弃的,所以每个字符都会参与运算,取大于1的奇数可行。

结论

由上面三步的推导可知,这个系数应当选择大于1的奇数,这样可以很好的降低碰撞的几率,那么我们就可以根据上面推导的公式,用代码实现:

bkdrhash的初步代码实现如下:

[cpp] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. #include <iostream>  
  2. #include <MATH.H>  
  3.   
  4. unsigned int str_hash_1(const char* s)  
  5. {  
  6.     unsigned char *p = (unsigned char*)s;  
  7.     unsigned int hash = 0;  
  8.     unsigned int seed = 3;//3,5,7,9,...,etc奇数  
  9.     unsigned int nIndex = 0;  
  10.     unsigned int nLen = strlen((char*)p);  
  11.     while( *p )  
  12.     {  
  13.         hash = hash + pow(3,nLen-nIndex-1)*(*p);  
  14.         ++p;  
  15.         nIndex++;  
  16.     }  
  17.     return hash;  
  18. }  
  19.   
  20. int main(int argc, char* argv[])  
  21. {  
  22.     std::cout << str_hash_1("hijklmn")<<std::endl;  
  23.     std::cout << str_hash_1("bhijklmn")<<std::endl;  
  24.     getchar();  
  25.     return 0;  
  26. }  
其实我们可以对代码进行简化,即利用递归进行实现,但是在使用bkdrhash时你会发现里面大多源码使用的都是特殊的奇数2^n-1,那是因为在CPU的运算中移位和减法比较快。代码如下:

[cpp] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. #include <iostream>  
  2.   
  3. unsigned int bkdr_hash(const char* key)  
  4. {  
  5.     char* str = const_cast<char*>(key);  
  6.               
  7.     unsigned int seed = 31; // 31 131 1313 13131 131313 etc.. 37  
  8.     unsigned int hash = 0;  
  9.     while (*str)  
  10.     {  
  11.         hash = hash * seed + (*str++);  
  12.     }  
  13.     return hash;  
  14. }  
  15.   
  16. int main(int argc, char* argv[])  
  17. {  
  18.     std::cout << bkdr_hash("hijklmn")<<std::endl;  
  19.     std::cout << bkdr_hash("bhijklmn")<<std::endl;  
  20.     getchar();  
  21.     return 0;  
  22. }  

扩展

注意:即使最终求得的bkdrhash值几乎不会冲突碰撞,但他们都是很大的值,不可能直接映射到哈希数组地址上,所以一般都是直接对哈希数组大小取余,以余数作为索引地址,但是这就造成了,可能的地址冲突。bkdrhash值不一样,但是取余后得到的索引地址一样,也就是冲突,只是这种冲突的概率很小。对于哈希表不可能完全消除碰撞,只能降低碰撞的几率。作为对哈希知识的进一步熟悉,下面罗列几点提升哈希表效率的注意点:

1.选用的哈希函数

            哈希函数的目的就是为了产生譬如字符串的哈希值,让不同的字符串尽量产生不同的哈希值的函数就是好的哈希函数,完全不会产生相同的哈希函数就是完美的。

2.处理冲突的方法

         处理冲突的方法有多种,拉链法、线性探测等,我喜欢用拉链法

3.哈希表的大小

         这个哈希表的大小是固定的,但可以动态调整,也就是创建个新的数组,用旧的给新的循环重新计算Key赋值,删除旧的。但最好根据需求数据量设置足够大的初始值,防止动态调整的频繁,因为调整是很费时又费空间的。还有重要的是,这个哈希表的大小要设为一个质数,为什么是质数?因为质数只有1和它本身两个约数,当用bkdrhash算得的key对哈希表大小取余时,不会因为存在公约数而缩小余数的范围,如果余数范围缩小的话,就会加大碰撞的几率(说法有点牵强,知道的童鞋请给个合理的解释)。

4.装载因子,即哈希表的饱和程度

一般来说装载因子越小越好,装载因子越小,碰撞也就越小,哈希表的速度就会越快,可是这样会大大的浪费空间,假如装载因子为0.1,那么哈希表只有10%的空间被真正利用,其余的90%都浪费了,这就是时间和空间的矛盾点,为了平衡,现在大部分采用的是0.75作为装载因子,装载因子达到0.75,那么就动态增加哈希表的大小。

哈希表的初步C++封装实现

[cpp] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. //my_hash_map.h  
  2. //哈希表的初步实现  
  3. //参考互联网资料实现  
  4. #pragma once  
  5. #define HASH_MAX_STRING_LEN 128  
  6. #include <WINDOWS.H>  
  7. template<typename objectType>   
  8. class my_strhash_map  
  9. {  
  10. protected:  
  11.     struct Assoc   
  12.     {  
  13.         Assoc()  
  14.         {  
  15.             memset(sKey,0,HASH_MAX_STRING_LEN);  
  16.             pData = NULL;  
  17.             pNext = NULL;  
  18.         }  
  19.         char sKey[HASH_MAX_STRING_LEN];  
  20.         objectType* pData;  
  21.         Assoc* pNext;  
  22.     };  
  23.   
  24.     typedef Assoc* LPAssoc;  
  25. public:  
  26.     struct iterator   
  27.     {  
  28.         friend class my_strhash_map;  
  29.         iterator()  
  30.         {  
  31.             m_pIter = NULL;  
  32.             m_nIndex = 0;  
  33.             m_pMap = NULL;  
  34.         }  
  35.         //前缀,如++i  
  36.         iterator& operator++()  
  37.         {  
  38.             if ( m_pIter->pNext )  
  39.             {  
  40.                 m_pIter = m_pIter->pNext;  
  41.                 return *this  
  42.             }  
  43.             for ( ULONG i=m_nIndex+1; i<m_pMap->m_nHashSize; i++ )  
  44.             {  
  45.                 if ( NULL != m_pMap->m_pHashTable[i] )  
  46.                 {  
  47.                     m_pIter = m_pMap->m_pHashTable[i];  
  48.                     m_nIndex = i;  
  49.                     return *this;  
  50.                 }  
  51.             }  
  52.             m_pIter = NULL;  
  53.             m_nIndex = 0;  
  54.             return *this;  
  55.         }  
  56.         //后缀 如i++  
  57.         const iterator operator++(int)  
  58.         {  
  59.             iterator tmp( m_pIter,m_nIndex,m_pMap );  
  60.             if ( m_pIter->pNext )  
  61.             {  
  62.                 m_pIter = m_pIter->pNext;  
  63.                 return tmp;  
  64.             }  
  65.   
  66.             for ( ULONG i=m_nIndex+1; i<m_pMap->m_nHashSize; i++ )  
  67.             {  
  68.                 if ( NULL != m_pMap->m_pHashTable[i] )  
  69.                 {  
  70.                     m_pIter = m_pMap->m_pHashTable[i];  
  71.                     m_nIndex = i;  
  72.                     return tmp;  
  73.                 }  
  74.             }  
  75.             m_pIter = NULL;  
  76.             m_nIndex = 0;  
  77.             return tmp;  
  78.         }  
  79.         objectType& operator *()  
  80.         {  
  81.             return *( m_pIter->pData );  
  82.         }  
  83.         bool operator== (const iterator& obj)  
  84.         {  
  85.             return m_pMap == obj.m_pMap && m_pIter == obj.m_pIter;  
  86.         }  
  87.         bool operator != (const iterator& obj)  
  88.         {  
  89.             return m_pMap != obj.m_pMap || m_pIter != obj.m_pIter;  
  90.         }  
  91.     protected:  
  92.         iterator(LPAssoc pAssoc,ULONG nIndex,my_strhash_map* map)  
  93.         {  
  94.             m_pIter = pAssoc;  
  95.             m_nIndex = nIndex;  
  96.             m_pMap = map;  
  97.         }  
  98.         LPAssoc m_pIter;  
  99.         ULONG m_nIndex;  
  100.         my_strhash_map* m_pMap;  
  101.   
  102.     };  
  103.     my_strhash_map(ULONG nInitSize = 199,BOOL bAutoIncr = TRUE)  
  104.     {  
  105.         m_bAutoIncr = bAutoIncr;  
  106.         m_nHashSize = 0;  
  107.         m_nCount = 0;  
  108.         m_nConflictCount = 0;  
  109.         m_pHashTable = NULL;  
  110.         InitMap(nInitSize);  
  111.     }  
  112.   
  113.     BOOL insert(const char* sKey,objectType obj)  
  114.     {  
  115.         if ( NULL == sKey || strlen(sKey) > HASH_MAX_STRING_LEN )  
  116.         {  
  117.             return FALSE;  
  118.         }  
  119.   
  120.         ULONG nHash = BkdrHashKey(sKey) % m_nHashSize;  
  121.         LPAssoc pAssoc = m_pHashTable[nHash];  
  122.         if ( NULL == pAssoc )  
  123.         {  
  124.             m_pHashTable[nHash] = new Assoc;  
  125.             strcpy(m_pHashTable[nHash]->sKey,sKey);  
  126.             m_pHashTable[nHash]->pData = new objectType(obj);  
  127.             m_pHashTable[nHash]->pNext = NULL;  
  128.             m_nCount++;  
  129.         }  
  130.         else  
  131.         {  
  132.             LPAssoc pAssocPre = pAssoc;  
  133.             while( pAssoc )  
  134.             {  
  135.                 //重复插入同一sKey,则返回  
  136.                 if ( 0 == strcmp(pAssoc->sKey,sKey) )  
  137.                     break;  
  138.                 pAssocPre = pAssoc;  
  139.                 pAssoc = pAssoc->pNext;  
  140.             }  
  141.             if ( NULL == pAssoc )  
  142.             {  
  143.                 pAssoc = new Assoc;  
  144.                 strcpy(pAssoc->sKey,sKey);  
  145.                 pAssoc->pData = new objectType(obj);  
  146.                 pAssoc->pNext = NULL;  
  147.                 pAssocPre->pNext = pAssoc;  
  148.                 m_nConflictCount++;  
  149.             }  
  150.         }  
  151.   
  152.         if ( m_nCount > m_nHashSize )  
  153.         {  
  154.             ReSetTableSize( AdjustSize(m_nCount) );  
  155.         }  
  156.         return TRUE;  
  157.     }  
  158.     BOOL Find(const char* sKey,objectType& obj)  
  159.     {  
  160.         if ( NULL == sKey || strlen(sKey) > HASH_MAX_STRING_LEN )  
  161.         {  
  162.             return FALSE;  
  163.         }  
  164.           
  165.         ULONG nHash = BkdrHashKey(sKey);  
  166.         nHash = nHash % m_nHashSize;  
  167.         LPAssoc pAssoc = m_pHashTable[nHash];  
  168.         while( pAssoc )  
  169.         {  
  170.             if ( 0 == strcmp(pAssoc.sKey,sKey) )  
  171.             {  
  172.                 obj = *(pAssoc->pData);  
  173.                 return TRUE;  
  174.             }  
  175.             pAssoc = pAssoc->pNext;  
  176.         }  
  177.         return FALSE;  
  178.     }  
  179.     BOOL Containts(const char* sKey)  
  180.     {  
  181.         if ( NULL == sKey || strlen(sKey) > HASH_MAX_STRING_LEN )  
  182.         {  
  183.             return FALSE;  
  184.         }  
  185.   
  186.         ULONG nHash = BkdrHashKey(sKey);  
  187.         nHash = nHash % m_nHashSize;  
  188.         LPAssoc pAssoc = m_pHashTable[nHash];  
  189.         while( pAssoc )  
  190.         {  
  191.             if ( 0 == strcmp(pAssoc->sKey,sKey) )  
  192.                 return TRUE;  
  193.             pAssoc = pAssoc->pNext;  
  194.         }  
  195.         return FALSE;  
  196.     }  
  197.   
  198.     void RemoveKey(const char* sKey)  
  199.     {  
  200.         if ( NULL == sKey )  
  201.             return;  
  202.         ULONG nHash = BkdrHashKey(sKey)%m_nHashSize;  
  203.         LPAssoc pAssoc = m_pHashTable[nHash];  
  204.         if ( pAssoc && strcmp(pAssoc->sKey,sKey) == 0 )  
  205.         {  
  206.             m_pHashTable[nHash] = pAssoc->pNext;  
  207.             delete pAssoc->pData;  
  208.             delete pAssoc;  
  209.             m_nCount--;  
  210.         }  
  211.         else  
  212.         {  
  213.             LPAssoc pAssocPre = pAssoc;  
  214.             pAssoc = pAssoc->pNext;  
  215.             while( pAssoc )  
  216.             {  
  217.                 if ( strcmp(pAssoc->sKey,sKey) == 0 )  
  218.                 {  
  219.                     pAssocPre->pNext = pAssoc->pNext;  
  220.                     delete pAssoc->pData;  
  221.                     delete pAssoc;  
  222.                     m_nConflictCount--;  
  223.                     break;  
  224.                 }  
  225.                 pAssocPre = pAssoc;  
  226.                 pAssoc = pAssoc->pNext;  
  227.             }  
  228.         }  
  229.     }  
  230.   
  231.     ULONG Size()  
  232.     {  
  233.         return m_nCount+m_nConflictCount;  
  234.     }  
  235.     void Clear()  
  236.     {  
  237.         LPAssoc pAssoc = NULL;  
  238.         LPAssoc pDelAssoc = NULL;  
  239.         for ( int i = 0;i < m_nHashSize;i++ )  
  240.         {  
  241.             pAssoc = m_pHashTable[i];  
  242.             while( pAssoc )  
  243.             {  
  244.                 pDelAssoc = pAssoc;  
  245.                 pAssoc = pAssoc->pNext;  
  246.                 delete pDelAssoc->pData;  
  247.                 delete pDelAssoc;  
  248.             }  
  249.             m_pHashTable[i] = NULL;  
  250.         }  
  251.         m_nCount = 0;  
  252.         m_nConflictCount = 0;  
  253.     }  
  254.     iterator begin()  
  255.     {  
  256.         for ( ULONG i=0; i<m_nHashSize; i++ )  
  257.         {  
  258.             if ( NULL != m_pHashTable[i] )  
  259.             {  
  260.                 return iterator(m_pHashTable[i],i,this);  
  261.             }  
  262.         }  
  263.         return iterator(NULL,0,this);  
  264.     }  
  265.     iterator end()  
  266.     {  
  267.         return iterator(NULL,0,this);  
  268.     }  
  269.     ULONG GetTableSize()  
  270.     {  
  271.         return m_nHashSize;  
  272.     }  
  273.     BOOL AutoIncrease()  
  274.     {  
  275.         return m_bAutoIncr;  
  276.     }  
  277. protected:  
  278.    
  279.     void ReSetTableSize(ULONG nSize)  
  280.     {  
  281.         LPAssoc* pNewAssocTable = new LPAssoc[nSize];  
  282.         memset( pNewAssocTable,0,sizeof((LPAssoc*)pNewAssocTable) );  
  283.         for ( ULONG i = 0;i < m_nHashSize;i++ )  
  284.         {  
  285.             LPAssoc pOldAssoc = m_pHashTable[i];  
  286.             while( NULL != pOldAssoc )  
  287.             {  
  288.                 ULONG nHash = BkdrHashKey(pOldAssoc->sKey)%nSize;  
  289.                 if ( NULL == pNewAssocTable[nHash] )  
  290.                 {  
  291.                     pNewAssocTable[nHash] = pOldAssoc;  
  292.                     pNewAssocTable[nHash]->pNext = NULL;  
  293.                 }  
  294.                 else  
  295.                 {  
  296.                     LPAssoc pAssocTemp = pNewAssocTable[nHash];  
  297.                     while( NULL != pAssocTemp->pNext )  
  298.                         pAssocTemp = pAssocTemp->pNext;  
  299.                     pAssocTemp->pNext = pOldAssoc;  
  300.                     pAssocTemp->pNext->pNext = NULL;  
  301.                 }  
  302.                 pOldAssoc = pOldAssoc->pNext;  
  303.             }  
  304.         }  
  305.   
  306.         delete[] m_pHashTable;  
  307.         m_pHashTable = pNewAssocTable;  
  308.         m_nHashSize = nSize;  
  309.     }  
  310.     void InitMap(ULONG nSize)  
  311.     {  
  312.         m_nHashSize = AdjustSize(nSize);  
  313.         if ( m_pHashTable )  
  314.         {  
  315.             delete[] m_pHashTable;  
  316.             m_pHashTable = NULL;  
  317.         }  
  318.   
  319.         m_pHashTable = new LPAssoc[m_nHashSize];  
  320.         memset(m_pHashTable,0,sizeof(LPAssoc)*m_nHashSize );  
  321.     }  
  322.     ULONG AdjustSize(ULONG nSize)  
  323.     {  
  324.         // 注意:假设 long 至少有 32 bits。    
  325.         //定义28个素数(大概是2倍关系增长),用来做hash table的大小  
  326.         const ULONG size_list[] = {  
  327.             53,         97,             193,        389,        769,  
  328.             1543,       3079,           6151,       12289,      24593,  
  329.             49157,      98317,          196613,     393241,     786443,  
  330.             1572869,    3145739,        6291469,    12582917,   25165842,  
  331.             50331553,   100663319,      201326611,  402653189,  805306457,  
  332.             1610612741, 3221225473ul,   4294967291ul  
  333.         };  
  334.         int nlistsize = sizeof(size_list) / sizeof(ULONG);  
  335.         int i = 0;  
  336.         for (;i<nlistsize;i++)  
  337.         {  
  338.             if ( size_list[i] >= nSize )  
  339.                 break;  
  340.         }  
  341.   
  342.         if ( i == nlistsize )  
  343.             i--;  
  344.         return size_list[i];  
  345.     }  
  346.   
  347.     ULONG BkdrHashKey(const char* key)   
  348.     {  
  349.         if (1)  
  350.         {  
  351.             char* str = const_cast<char*>(key);  
  352.               
  353.             unsigned int seed = 31; // 31 131 1313 13131 131313 etc.. 37  
  354.             unsigned int hash = 0;  
  355.               
  356.             while (*str)  
  357.             {  
  358.                 hash = hash * seed + (*str++);  
  359.             }  
  360.               
  361.             return (hash & 0x7FFFFFFF);  
  362.         }  
  363.           
  364.         if ( NULL == key )  
  365.             return 0;  
  366.         ULONG nHash = 0;  
  367.         while (*key)  
  368.             nHash = (nHash<<5) + nHash + *key++;  
  369.         return nHash;  
  370.     }  
  371.   
  372. protected:  
  373.     ULONG m_nHashSize;              //哈希表大小  
  374.     ULONG m_nCount;                 //哈希表中当前元素个数  
  375.     ULONG m_nConflictCount;         //哈希表中冲突的个数  
  376.     LPAssoc* m_pHashTable;          //哈希表头指针  
  377.     BOOL m_bAutoIncr;               //是否自动调整表大小  
  378.   
  379.   
  380. };  

0 0
原创粉丝点击