看了July关于暴雪Hash算法的讲解,有几个地方没理解。
原文地址 http://blog.csdn.net/v_JULY_v/article/details/6256463
http://blog.csdn.net/v_july_v/article/details/7085669
暴雪hash与普通hash不同的是,使用了更好的hash值
使用3个hash值,一个用于查找,两个用于校验
如果出现冲突,寻找下一个,如果到了数组尾部还没找到,则表示字符串不存在。
那么最大的不同应该就是使用三个hash值,在比较的时候不直接比较字符串而比较另外两个hash值,另外为啥不使用链表呢?
先把july的代码贴上来
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <ctype.h> //多谢citylove指正。 #include <string.h> #include <stdlib.h> //crytTable[]里面保存的是HashString函数里面将会用到的一些数据,在prepareCryptTable //函数里面初始化 const int nTableSize = 2000; const int nMaxStrLen = 2000; unsigned long cryptTable[0x500]; typedef struct _a { int nHashA; int nHashB; char bExists; } MPQHASHTABLE; ///////////////////////////////////////////////////////////////////// //function: 哈希词典 编码 //parameter: //author: lei.zhou //time: 2011-12-14 ///////////////////////////////////////////////////////////////////// MPQHASHTABLE TestHashTable[nTableSize]; //以下的函数生成一个长度为0x500(合10进制数:1280)的cryptTable[0x500] void prepareCryptTable() { unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i; for (index1 = 0; index1 < 0x100; index1++) { for (index2 = index1, i = 0; i < 5; i++, index2 += 0x100) { unsigned long temp1, temp2; seed = (seed * 125 + 3) % 0x2AAAAB; temp1 = (seed & 0xFFFF) << 0x10; seed = (seed * 125 + 3) % 0x2AAAAB; temp2 = (seed & 0xFFFF); cryptTable[index2] = (temp1 | temp2); } } } //以下函数计算lpszFileName 字符串的hash值,其中dwHashType 为hash的类型, //在下面GetHashTablePos函数里面调用本函数,其可以取的值为0、1、2;该函数 //返回lpszFileName 字符串的hash值; unsigned long HashString(const char *lpszFileName, unsigned long dwHashType) { unsigned char *key = (unsigned char *)lpszFileName; unsigned long seed1 = 0x7FED7FED; unsigned long seed2 = 0xEEEEEEEE; int ch; while (*key != 0) { ch = toupper(*key++); seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2); seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3; } return seed1; } //直接调用上面的hashstring,nHashPos就是对应的HASH值。 int insert_string(const char *string_in) { const int HASH_OFFSET = 0, HASH_C = 1, HASH_D = 2; unsigned int nHash = HashString(string_in, HASH_OFFSET); unsigned int nHashC = HashString(string_in, HASH_C); unsigned int nHashD = HashString(string_in, HASH_D); unsigned int nHashStart = nHash % nTableSize; unsigned int nHashPos = nHashStart; int ln, ires = 0; while (TestHashTable[nHashPos].bExists) { // if (TestHashCTable[nHashPos] == (int) nHashC && TestHashDTable[nHashPos] == (int) nHashD) // break; // //... // else //如之前所提示读者的那般,暴雪的Hash算法对于查询那样处理可以,但对插入就不能那么解决 nHashPos = (nHashPos + 1) % nTableSize; if (nHashPos == nHashStart) break; } ln = strlen(string_in); if (!TestHashTable[nHashPos].bExists && (ln < nMaxStrLen)) { TestHashTable[nHashPos].nHashA = nHashC; TestHashTable[nHashPos].nHashB = nHashD; TestHashTable[nHashPos].bExists = 1; } else { if (TestHashTable[nHashPos].bExists) printf("30000 in the hash table %s !!!\n", string_in); else printf("90000 strkey error !!!\n"); } return nHashPos; } int GetHashTablePos(char *lpszString, MPQHASHTABLE *lpTable, int nTableSize) { const int HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2; unsigned int nHash = HashString(lpszString, HASH_OFFSET); unsigned int nHashA = HashString(lpszString, HASH_A); unsigned int nHashB = HashString(lpszString, HASH_B); unsigned int nHashStart = nHash % nTableSize; unsigned int nHashPos = nHashStart; while (lpTable[nHashPos].bExists) { /*如果仅仅是判断在该表中时候存在这个字符串,就比较这两个hash值就可以了,不用对 *结构体中的字符串进行比较。这样会加快运行的速度?减少hash表占用的空间?这种 *方法一般应用在什么场合?*/ if (lpTable[nHashPos].nHashA == nHashA && lpTable[nHashPos].nHashB == nHashB) { return nHashPos; } else { nHashPos = (nHashPos + 1) % nTableSize; } if (nHashPos == nHashStart) break; } return -1; } int main(int argc, char **argv) { unsigned long ulHashValue; /*初始化数组:crytTable[0x500]*/ prepareCryptTable(); insert_string("121"); insert_string("1211"); insert_string("1221"); insert_string("12121"); insert_string("1121"); insert_string("1 21"); insert_string("12 1"); /*打印数组crytTable[0x500]里面的值*/ printf("\n ===%d ", GetHashTablePos("1 21", TestHashTable, nTableSize)); return 0; }
我的思路,不知道对不对,求改正
既然已经有了三个hash值,并且三个hash值都相同的概率极低,那么为何不直接利用这三个hash值来查找呢
意思是,将一个大的数组分为n个小数组(人为的),比如大数组长度10000,我分为10个小数组,那么每个小数组长度为1000,0-999,1000-1999,。。。。。。。。。
第二层,同样的利用第二个hash值,将上面的小数组在分,
第三层,同上,不知道这样效率会不会更高。
写个代码试试