zoukankan      html  css  js  c++  java
  • 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点半

  • 相关阅读:
    163.扩展User模型-一对一方式扩展
    162.扩展User模型-使用Proxy模型
    161.内置User模型的基本使用
    160.验证和授权系统的概述
    159.SQL注入的实现和防御措施
    OS课程 ucore_lab2实验报告
    IdentityServer4专题之七:Authorization Code认证模式
    IdentityServer4专题之六:Resource Owner Password Credentials
    IdentityServer4专题之五:OpenID Connect及其Client Credentials流程模式
    IdentityServer4专题之四:Authorization Endpoint、Token Endpoint、scope、Access Token和Refresh Token、授权服务器发生错误
  • 原文地址:https://www.cnblogs.com/lancidie/p/1982250.html
Copyright © 2011-2022 走看看