Hash基础知识点

概念:

 Hash 是“杂乱信息”的意思。

 Hash表是将一堆杂乱得信息,根据它们的关键词特点,将其映射到一个连续的空间上。这种映射关系称作索引方法 ,对应的实现函数叫哈希函数,同时将关键词映射后的值叫做关键词的索引。

  索引实际上就是数组的下标,数组的每一个位置习惯上也被称作桶(bucket),在哈希表中桶和索引的叫法是等价的。

哈希表的索引方法:

  • 整除取余法

/** 哈希表的计算整数的索引函数
@param UINT uKey——关键词
@param UINT uBucketCount——哈希表的大小,用来做整除的模 
@return UINT——索引值
*/

UINT HashIndexClac_Int(UINT KeyValue, UINT ModelValue)
{
    UINT Index = 0;
    Index = KeyValue % ModelValue;
    return Index;
}

优点 :一个连续的序列或者接近一个连续系列,效果最好。
缺点 :1)需要求出一个使关键词索引尽量不相同的最小 nMod 来。当然 nMod 不能太大,因为最后得出的余数可能为 nMod-1,所以表的大小必须大于 nMod-1,当 nMod 太大时意味着需要表的辅助空间太大。
       2)只能对计算机硬件能够处理的整数进行计算,如32 位 CPU 硬件最大能处理的整数是 2^32 =4294964296

  • 折叠法

       当关键词位数很多时,可以将关键词分割成位数相同的几部分,每部分可以转换成一个计算机可以处理的整数,然后将各部分转换后的整数相加,得到一个新的整数,这就是折叠法。折叠法最后得到的那个新的整数不能直接作为关键词的索引,还需要使用整除取余法来得到关键词的索引。
/** 字符串类型数据的关键词索引计算函数,将字符串折叠成每 5 个字符一段,每段看成
八进制整数,将各段相加后再取余数
@param void *pStr——字符串指针 
@param UINT uBucketCount——最大 bucket 的个数,被用来做为整除的模 
@return UINT——字符串关键词的索引 
*/
UINT HashIndexClac_String(VOID * StringValue, UINT ModelValue)
{
        unsigned char *psz;
        UINT HashValue = 0;
        UINT Ret       = 0;
        UINT i         = 0;
        UINT t         = 0;
        psz = (unsigned char *)StringValue;
        while (*psz != '\0')
        {
            if (i == 5)
            {
                i = 0;
                Ret += HashValue;
                HashValue = 0;
            }
            t = HashValue << 3;
            HashValue = HashValue + t;
            HashValue = HashValue + (UINT)(*psz);
                psz++;
                i++;
        }
    Ret += HashValue;
        return HashIndexClac_Int(Ret, ModelValue) ;
}
       采用折叠法的计算开销比整除取余法大很多,因为它要将关键词中的每个字节都计算一遍,但它的好处是计算出的索引很少会重复。在数据较多的情况下,使用这种方法效果是很好的。

  • 平方取中法

       顾名思义,平方取中法是将关键词进行平方运算后,再取运算结果的中间几位作为索引。通常一个数经平方运算后,其结果的中间几位和数的每一位都相关,具体取多少位则需要由表的长度来决定。

  • 随机函数法 

       随机函数法是设计一个产生随机数的函数,以关键词作为随机函数的输入,函数的计算结果作为索引。采用随机函数法,在产生随机数时一般也要用到整除取余,实际上是整除取余法的一个扩展。

不管采用何种方法计算索引,都会对以下几个方面产生影响:
① 计算索引所需要的时间(建议最大不要超过 12 次比较的时间);
② 每次查找关键词的平均比较次数(建议最大不要超过 5 次);
③ 最坏情况下的比较次数(建议最大不要超过 50 次);
④ 哈希表所需要的辅助空间 (建议不要超过实际关键词个数的两倍大小)。 

哈希冲突

  原因:由于哈希算法被计算的数据是无限的,而计算后的结果范围有限,因此总会存在不同的数据经过计算后得到的值相同,这就是哈希冲突。

解决方法:

  • 开放定址法

      将所有的输入都元素全部放在哈希表中,不需要任何链表来完成,当发生哈希冲突饿时,根据再寻址方法,去寻找下一个地址,直到找到一个空位置。

       再寻址方法:

  • 线性探测

   按顺序决定哈希值时,如果某数据的哈希值已经存在,则在原来哈希值的基础上往后加一个单位,直至不发生哈希冲突。 

  • 二次探测

   按顺序决定哈希值时,如果某数据的哈希值已经存在,则在原来哈希值的基础上先加1的平方个单位,若仍然存在则减1的平方个单位。随之是2的平方,3的平方等等。直至不发生哈希冲突。

  • 伪随机探测

  按顺序决定哈希值时,如果某数据已经存在,通过随机函数随机生成一个数,在原来哈希值的基础上加上随机数,直至不发生哈希冲突。

 

  • 链地址法

   对于相同的哈希值,使用链表进行连接。

优点:

  (1)拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;

  (2)由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;

  (3)开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;

  (4)在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。
  缺点:

  指针占用较大空间时,会造成空间浪费,若空间用于增大散列表规模进而提高开放地址法的效率。

 

  • 公共溢出区

  将所有产生哈希冲突的数据储存再公共溢出区。

  • 再HASH法

   对产生哈希冲突的数据,重新哈希计算,直到没有哈希冲突。时间、性能会有影响。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值