数据结构与算法-散列表冲突的解决办法

我们上文以字典作为例子,描述了散列表这种结构。

它以函数H(哈希函数)作为纽带,连接一对键值,通过H(键)计算得出数组的下标用于存储键值对。

它的优势是可以绑定键值,允许我们通过键来访问特定的值,并且寻找的复杂度不精准的来说是O(1)。

但是我们发现了问题,我们的数组是有限长度的,但是输入在某些情况下,不同的键可能会得到同样的下标,即产生了冲突。

如这两个图所示,键值1和存储之后,键值2得到的下标是一样的,但是该位置已经存储了键值1.

对于这种问题,有多种方法缓和,这里仅仅介绍其中两种典型的思路。

 

开放地址法

它的原意就是我们在发生冲突的时候,就继续寻找其他其他的可用地址,即所谓的“开放”。

开放地址法采用顺位寻找的方法,当地址d已经被占用,那么就尝试在d+1(1指的是一个单元的大小,不是一字节等)位置,如果也被占用那么就再往下一位,直到可用为止。

我们向下查找发现2位置可用,那么就将键值2存储到该位置。顺序向下查找法是比较简单的,但查找的方式不仅仅只有这个,这里只是做一个简单的例子。

这是我们发现,查找键值对的时间复杂度可能就不是O(1)了,假设该情况下,寻找键2的值,当H(键2)得到下标1之后发现里面存储的键不是键2,那么就需要按照存储时时候的方法继续向下判断,可知下标为2的位置存储着我们要查找的键值。但数目较多时,如果存在大量的冲突,那么查找的时候也会变得很麻烦。

 

链表法

前文我们说过链表,通过指针将散乱在内存的节点连接到一起,是跟数组不一样的一种非线性结构。那么我们为什么非要在数组中将可能冲突的键值存储在一起呢。链表给了我们一个启发,当发生冲突时,如果使用链表将下标一样的键存储起来,不就不用担心数组混乱了吗,为了实现这个功能我们需要将存储的数组改造一下,加上一个尾指针

键值对1和3发生了冲突,此时我们在下标1的链表后加入新的节点,用来存储键值3

实际上我们要的效果就是这样的

当我们根据键定位键值存储位置时,如果链表第一个节点就是要找的那么就直接返回值,否则的话需要做的就是遍历链表找到目标键值,链表的遍历我们已经说过了哈。

 

起始哈希冲突的解决方法还有很多,其中不乏比较巧妙的方法,感兴趣的可以查一查。

 

总的来说,在编程中散列表是我们常用的,也十分重要的一种数据类型。它独特的访问和存储机制,为我们带来了很大的便利。除此之外,还有其他两个非常重要的数据结构数和图,这个跟前面的相比就比较高深一些,将会在后续的文章中继续讲解。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值