哈希第一弹:哈希的概念、哈希函数以及哈希冲突的解决方法

哈希的概念: 

哈希表查找的基本思想是:根据当前带查找数据的特征,以记录关键字为自变量,设计一个哈希函数,以该函数按关键码计算该元素的存储位置,并按此存放;查找时,有同一个函数对给定值key计算地址,将key与地址单元中元素关键码进行比较,确定查找是否成功。哈希方法中使用的转换函数称为哈希函数,按这个思想构造的表称为哈希表(散列表)

 

从上面的概念,构建哈希表关键是有哈希函数。那么我们来看看常见的哈希函数有哪些?

 

常见哈希函数:

直接定值法:

  • 取关键字的某线性函数为哈希地址:Hash(Key) = A*Key +B ;

eg: 4 6 7 8 9          Hash(Key) =Key

    4 6789

 

                                                      0            1         2      3          4         5          6          7            8              9 

直接定制法,比较好的一点就是简单,直接映射;  不过也有缺点:映射的数据集合应该是分布集中,连续的 

 eg:1    100000000000

如果只映射两个数1和一个超大的数,直接映射,我们需要开很大的空间,并且空间严重浪费,这就是直接定制法的巨大缺陷

 除留余数法:

  •        假设散列长度为m,取一个不大于m但最接近或者等于m的质数p作为除数
  •        按照哈希函数 Hash(key) =key%p,将关键码转换成哈希地址

 

 除留余数法,很大程度解决了直接定制法的空间浪费问题。

 不常用的哈希函数

 平方取中法

  •             先计算关键字的平方,再抽取中间的几个数作为哈希地址

  eg :          

关键字平方哈希地址(抽取了中间3位)
12341522765227
432118671041710(671也可以)

 用平方取中法,关键字的位数不能太大。太大的话,最早的情况,平方之后如果超过long  long,很难操作

折叠法

  •   将关键字从左到右分隔成位数相等的几部分(最后一部分位数可以短一些)
  •  再将这几部分叠加求和,并按散列表表长,取后几位最为散列地址   

 

 折叠法可以适用于关键字位数较大的情况

 随机数法:

  •  选择一个随机函数,取关键字的随机函数值为哈希地址;
  • 即Hash(key)=random(key)
  • 通常应用于关键字长度不等时采用这种方法

 数字分析法:

  •       如果有n个d位数,每一位上可能由r中不同的符号,这种r中不同的符号在各个位上出现的概率不一定相同,可能在某些位上分布比较均匀,每种符号出现的机会均等,在某些位上分布不均匀,只有某几种符号常见。
  • 我们就可以根据散列表的大小,选择其中各个符号分布均匀的若干位作为散列地址。
  • 通常用于关键字位数表加大,并且实现直到关键字的若干位分布均匀的情况

 总之,设计哈希函数的目的,一是为了映射到哈希表上,二是为了减少产生哈希冲突的可能性(无法完全避免哈希冲突) 

 

可能刚才提到哈希冲突,大家有点迷惑什么是哈希冲突?

接下来,我们就讨论一下哈希冲突及其解决方法。我们主要讨论的哈希函数为直接定制法和除余留数法。

哈希冲突

哈希的概念简单的说就是将关键字映射到表(哈希表)上的某个位置,查询的时候,到这个位置上去找;

那哈希冲突呢? 冲突,就是我们常说的矛盾。即多个关键字,经过哈希函数计算,映射到相同的位置,此时就有了矛盾,这个位置该存哪个关键字呢!这也就是我们说的哈希冲突 

 以我们上文用到的除余留数法为例,理解哈希冲突

 上面我们也提到了哈希冲突是不可避免的(当然,直接定值法,进行一 一映射的情况,可以视为特殊),所以我们需要解决方法:

哈希冲突的解决方法

闭散列(开放定址法):

 当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把关键字存放到冲突位置中的“下一个”空位置中去。

            如何寻找下一个空位置呢?

   线性探测:

           从发生冲突的位置开始,依次向后探测,直到寻找下一个空位置为止

  二次探测:

         从发生冲突的位置开始,找下一个空位置,查找空位置的方法为H_{i}=(H_{0}+i^2)%mH_{0}+i^2)%m,i=1,2,3........;m是哈希表大小,H_{0}是经过关键字计算后的出的哈希地址

开散列(链地址法、开链法)

 对关键字集合用散列函数计算散列地址,具有相同地址的关键码归于同一个子集合,每一个子集和称为一个桶,各个桶中的元素通过一个单链表连接起来,各链表的头结点存储在哈希表中。

举例理解上面三种解决哈希冲突的方法

线性探测:

从4这个位置开始查找下一个空位置,到5这个位置的时候,发现没有关键字存放,则把444放在5这个位置,倘若又要插入4444,则又要从4这个位置查找下一个空位置,发现6这个位置没有关键字存放,则把4444放到6这个位置;

 

看图解:

 二次探测:

当插入444时,i=1,经过计算,判断5的位置是否有关键字存放,发现没有,则将444存放在5这个位置

当在插入4444时,i=2,经过计算,判断8的位置是否有关键字存放,发现没有,则将4444存放在8这个位置

 

 开链法:

桶结构,将相同关键字存放在一个桶上。

 

 

 

注:如果本篇博客有任何错误和建议,欢迎伙伴们留言,你快说句话啊!

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值