暴雪hash算法,(不理解?稍作改进?)

看了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值,将上面的小数组在分,

第三层,同上,不知道这样效率会不会更高。

写个代码试试

 

你可能感兴趣的:(暴雪hash)