散列之可扩散列算法分析及实现

  最近在复习《数据结构与算法分析-C语言描述》,第5章散列中的可扩散列,书上的例子没有给出具体实现,因此我写下这篇博客来记录学习笔记。

  首先我先简单介绍一下散列,散列是一种用于存储、查找的数据结构,每一个关键字被被映射到从0到Tablesize-1这个范围中(最简单的是用数组来做成散列表,Tablesize-1 相当于数组的最大范围),这些关键字通过某一特殊函数进行映射,将关键字放在适当的单元中。比如最简单数组结构就可构成散列表,散列表存储一个新的Key的时候,使用Key mod Tablesize这个公式来分配对应的单元格。下图是一个 Tablesize=7 的散列表。我们先插入一个 key=10,分配的单元是index = Key mod Tablesize,即 index = 10%7, index = 3, 故在下标为3的位置插入key=10,对于其他的插入也是按照这个函数进行映射来分配单元。

==== 插入key=3后 ====》

但是,这样的插入会出现一个叫“冲突”的现象,比如我们在插入一个key=17时,index=3但是3这个单元已经有元素存在了无法插入到这,这里我简述使用开放定址发来解决冲突(还有一种叫分离链接法),我们这里使用线性探测法来查找单元,即使用F(i)=i 这个函数来查找单元( i是指查找的次数)。这个函数怎么用?我们继续刚刚的插入key=17,首先我们使用 index=17%7,index=3但是该单元已被分配,则 i=1 我们需往后查找可插入的单元 index = (index+i)%Tablesize,若后面的单元依旧不为空则 i=2 再往后找 index = (index+i)%Tablesize,直到找到空单元。插入key=17后如下图。我们再插入key=3,key=24, key=31效果如下图

====插入3,24,31后====》

不过现在比较流行的是平方探测法,F(i)=i^2,与上方的线性探测法类似,比如插入key=17,第一次找不到 i=1, index = (index +(i^2))%Tablesize,再插入key=3,查找了2次才找到 i=2, index = (index+i^2)%Tablesize,插入效果如图。

  但是,数组的空间是有限的,当散列表中剩余的可插入单元只剩下不足30%的时候插入效率会非常差,因此我们提出了再散列的说法,即申请一个比原来大两倍的空间的散列表,再将原本散列表中的元素重新散列到新的散列表。这个操作不算很难,但是还有一种解决方法叫可扩散列,即当空间不足时进行开辟一个与原来散列表空间一致的散列表,然后重新将散列表中的元素,分别散列到新、旧的散列表中。如我们按照比特前缀相同的规则进行散列,如下图

接下来我们插入一个关键字 100100,他会被散列到第三个散列表中,但是第三个散列表已经满了,因此需要进行可扩散列,如下图:

这种结构有点抽象,似乎好像很复杂比较难实现。我在实现这个例子的可扩散列的时候将他的结构稍微修改了一下。如图下:

修改成这样以后,你会发现他很像一颗二叉树,而前缀只需要通过从根节点到目标节点组合其节点的0或1即可得到前缀,进行可扩散列的时候仅仅时进行简单的二叉树插入节点,这种结构的可扩散列基本操作与二叉树相同,炒作起来方便,且清晰。

  接下来,我给这个结构设计了一道题,用于实现这个结构,我将关键字改为普通整数,但是我将他化作二进制数来进行以上操作,如:我插入31,上面的都是6位的故我31换作二进制(011111)插入以上的结构中,得下图:

 

我设计了一个用于实现以上结构得C++代码,代码不粘贴到此,可以通过后面的Git资源网站获取。

Git资源网站:https://github.com/AuthorityWu/Algorithm/tree/master/algorithm/hashing

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值