看了July关于暴雪Hash算法的讲解,有几个地方没理解。
原文地址 http://blog.youkuaiyun.com/v_JULY_v/article/details/6256463
http://blog.youkuaiyun.com/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值,将上面的小数组在分,
第三层,同上,不知道这样效率会不会更高。
写个代码试试