暴雪娱乐的hash表

具体流程就是创建一个较大的数组,然后通过特定的算法,将字符串转成整数,然后存入到这个数组中,然后可以通过取模,获得这个string在数组中的下标。

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define MAXMPQHASHTABLELEN 8192

typedef struct {

    long nHashA;
    long nHashB;
    unsigned int bExists;
}MPQHASHTABLE;

unsigned long cryptTable[0x500];

unsigned long HashString(char *lpszString, unsigned long dwHashType);
unsigned int MPQHashTableInit(char **ppHashTable, long nTableLength);
void MPQHashTableFree(char *pHashTable);
unsigned int MPQHashTableAdd(char *lpszString, char *pHashTable);
long MPQHashTableIsExist(char *lpszString, char *pHashTable);


static void InitCryptTable()
{
    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);
        }
    }
}

/*
函数名:HashString
功能:计算字符串的哈希值
参数:lpszString:字符串的地址
         dwHashType:哈希值类型
         dwHashType = 0时计算的哈希值用于确定字符串在哈希表中的位置;
            dwHashType = 1,dwHashType = 2时计算的哈希值用于验证字符串
返回值:字符串的哈希值
*/
unsigned long HashString(char *lpszString, unsigned long dwHashType)
{
    unsigned char *key = (unsigned char *)lpszString;
    unsigned long seed1 = 0x7FED7FED, 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;
}

/*
函数名:MPQHashTableInit
功能:初始化哈希表
参数:*ppHashTable:返回分配的哈希表的地址
        nTableLength:哈希表的长度
返回值:0:失败
            1:成功
*/
unsigned int MPQHashTableInit(char **ppHashTable, long nTableLength)
{
    long i = 0;
    char *p = NULL;
    MPQHASHTABLE *_pHashTable = NULL;

    InitCryptTable();

    p = malloc(nTableLength * sizeof(MPQHASHTABLE));
    if (p == NULL)
    {
        printf("%s, %d: malloc failed!\n", __FUNCTION__, __LINE__);
        return 0;
    }
    *ppHashTable = p;
    _pHashTable = (MPQHASHTABLE *)p;

    for (i = 0; i < nTableLength; i++)
    {
        (_pHashTable + i)->nHashA = -1;
        (_pHashTable + i)->nHashB = -1;
        (_pHashTable + i)->bExists = 0;
    }

    return 1;
}

/*
函数名:MPQHashTableFree
功能:释放哈希表
参数:pHashTable:哈希表的地址
返回值:无
*/
void MPQHashTableFree(char *pHashTable)
{
    if (pHashTable != NULL)
    {
        free(pHashTable);
        pHashTable = NULL;
    }
}

/*
函数名:MPQHashTableAdd
功能:将字符串的信息加入哈希表
参数:lpszString:字符串的地址
         pHashTable:哈希表的地址
返回值:0:失败
            1:成功
*/
unsigned int MPQHashTableAdd(char *lpszString, char *pHashTable)
{
    const unsigned long HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
    unsigned long nHash = HashString(lpszString, HASH_OFFSET);
    unsigned long nHashA = HashString(lpszString, HASH_A);
    unsigned long nHashB = HashString(lpszString, HASH_B);
    unsigned long nHashStart = nHash % MAXMPQHASHTABLELEN;
    unsigned long nHashPos = nHashStart;
    MPQHASHTABLE *_pHashTable = (MPQHASHTABLE *)pHashTable;
    while ((_pHashTable + nHashPos)->bExists)
    {
        nHashPos = (nHashPos + 1) % MAXMPQHASHTABLELEN;

        if (nHashPos == nHashStart)
        {
            return 0;
        }
    }

    (_pHashTable + nHashPos)->nHashA = nHashA;
    (_pHashTable + nHashPos)->nHashB = nHashB;
    (_pHashTable + nHashPos)->bExists = 1;

    return 1;
}

/*
函数名:MPQHashTableIsExist
功能:判断某字符串在哈希表中是否存在
参数:lpszString:字符串的地址
         pHashTable:哈希表的地址
返回值:-1:不存在
            nHashPos 该字符串在哈希表中的索引值
*/
long MPQHashTableIsExist(char *lpszString, char *pHashTable)
{
    const unsigned long HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
    unsigned long nHash = HashString(lpszString, HASH_OFFSET);
    unsigned long nHashA = HashString(lpszString, HASH_A);
    unsigned long nHashB = HashString(lpszString, HASH_B);
    unsigned long nHashStart = nHash % MAXMPQHASHTABLELEN;
    unsigned long nHashPos = nHashStart;
    MPQHASHTABLE *_pHashTable = (MPQHASHTABLE *)pHashTable;

    while ((_pHashTable + nHashPos)->bExists)
    {
        if (((_pHashTable + nHashPos)->nHashA == nHashA) && 
            ((_pHashTable + nHashPos)->nHashB == nHashB))
        {
            return nHashPos;
        }
        else
        {
            nHashPos = (nHashPos +1) % MAXMPQHASHTABLELEN;
        }
        if (nHashPos == nHashStart)
        {
            break;
        }
    }
    return -1;
}



int main(int argc,char ** argv)
{
    char* htable;
    MPQHashTableInit(&htable,MAXMPQHASHTABLELEN); //初始化hash表

    for(int i=0;i<argc;++i)
    {
        MPQHashTableAdd(argv[i],htable); //向hash表里面添加内容
    }

    printf("%ld\n",MPQHashTableIsExist("xxxxxxxx",htable));
    printf("%ld\n",MPQHashTableIsExist("k123",htable));
    printf("%ld\n",MPQHashTableIsExist("k_123",htable));
    printf("%ld\n",MPQHashTableIsExist("123k",htable));

    return 1;
}

clipboard.png


paulli3
992 声望8 粉丝

源码疯狂痴迷爱好者