这是一个“几乎完美”的哈希算法:
MPQ Hash
在星际争霸存档文件中使用。该算法非常高效,并且碰撞可能性非常低(平均约为 1:18889465931478580854784)。
这是该算法的工作原理。
1.计算三个哈希(偏移哈希和两个校验哈希)并将它们存储在变量中。
2.移动到偏移哈希的入口
3.该条目是否未使用?如果是这样,停止搜索并返回“找不到文件”。
4.这两个校验哈希是否与我们要查找的文件的校验哈希匹配?如果是,则停止搜索并返回当前条目。
5.移动到列表中的下一个条目,如果我们在最后一个条目上,则绕到开头。
6.我们刚刚移动到的条目是否与偏移哈希相同(我们是否查看了整个哈希表?)?如果是这样,停止搜索并返回“找不到文件”。
7.返回步骤 3。
这里是散列和散列表函数:
unsigned long HashString(char *lpszFileName, unsigned long dwHashType)
{
//lpszFileName is the string to be hashed.
//dwHashType will change the hash value according to hash mode.
//You can see how it's used in the beginning of GetHashTablePos().
unsigned char *key = (unsigned char *)lpszFileName;
unsigned long seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;
int ch;
while(*key != 0)
{
ch = toupper(*key++); //Convert every character to upper case.
//dwHashType will change the hash value in different hashing modes.
//(Whether to calculate the position or to verify.)
seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
}
return seed1;
}
int GetHashTablePos(char *lpszString, MPQHASHTABLE *lpTable, int nTableSize)
{
const int HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
//nHash controls where the hash value of the string should be stored in the hash table.
//nHashA and nHashB are used for verifying the match
int nHash = HashString(lpszString, HASH_OFFSET),
nHashA = HashString(lpszString, HASH_A),
nHashB = HashString(lpszString, HASH_B),
nHashStart = nHash % nTableSize, nHashPos = nHashStart;
while (lpTable[nHashPos].bExists)
{
if (lpTable[nHashPos].nHashA == nHashA && lpTable[nHashPos].nHashB == nHashB)
return nHashPos; //If found, return the entry index
else
nHashPos = (nHashPos + 1) % nTableSize; //Not found, move to next position
if (nHashPos == nHashStart)
break; //Reach the beginning of table, stop searching.
}
return -1; //Error value
}