Hash算法说明

Author: FreeKnight

Hash表本身是很容易理解的,它本身是一个固定大小的数组,数组的每个元素是一个链表的头指针。

我们对需要插入的元素,根据Hash算法算出一个对应的key,然后填充到对应的链表内做为尾节点。

遍历的时候,我们先对需查找的元素计算其Key,直接通过数组找到其所在链表,此时仅对其所在链表进行遍历即可。

但是,我们可以发现Hash表有以下问题。

1:若Hash算法得到的值范围很大,那么,表数组会比较大,是无谓的内存浪费。

2:若Hash算法得到的值范围很小,Key重复就会很高,遍历时查找的链表节点就太多,无法体现效率。

所以合适的Hash算法是Hash表性能的关键。

根据各种数学家的检测(这里,俺不管为啥……)哈希表尺寸最好使用质数,而实际上Hash表若使用动态的HashKey则会更加合适。我们从MPQ Hash里得到这些HashKey。

17,37,79,163,331,673,1361,2729,5471,10949,21911,43853,87719,175447,350899,701819,1403641,2807303,5614657,11229331,22458671,44917381,89834777,179669557,359339171,718678369,1437356741,2147483647。

当我们的元素数量为哈希表数组2倍时,我们就扩大一次哈希Key即可实现动态Hash,适用范围更大。

哈希算法有几个比较经典的。因为时间关系不再解释和说明。

//=====================================================

简单的比较均匀分布的Hash:

//=====================================================

unsigned long getHashIndex( const char *key, int nTableLength )
{
unsigned long nHash = 0;

while (*key)
{
nHash = (nHash<<5) + nHash + *key++;
}

return ( nHash % nTableLength );
}

//=====================================================
略复杂的MPQ哈希:

//=====================================================

以下的函数生成一个长度为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 );

   }

  }

}

//=====================================================

Blizzard的"One-Way Hash"算法,高效经典。

//=====================================================

unsigned long HashString( 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;

    }

}

看代码时候要定时……OMG,又3点半

原文地址:https://www.cnblogs.com/lancidie/p/1982250.html