数据结构与算法 / 散列表(HashTable)

本文深入探讨了散列表的工作原理,包括散列函数设计、冲突解决策略如开放寻址法和链表法,以及装载因子对性能的影响。此外,还讨论了散列表在Office Word拼写检查和URL访问统计等实际场景中的应用。

一、散列思想

       通过散列函数通过 Key 值计算得出数组下标,然后利用数组支持下标随机访问的特性,在时间复杂度为O(1)的情况下找到所需要的信息。

              散列函数

       Key -------------> 散列值(哈希值)

            (哈希函数)

二、散列函数

       顾名思义,其是一个函数,函数原型大概如下:

        size_t hash(key);

       要求,

              1、散列值是非负整数

              2、若 key1 = key2,则 hash(key1) == hash(key2) 。

              3、若 key1 != key2,则 hash(key1) != hash(key2) 。

       设计原则,

              1、散列函数的设计不能太复杂,否则会消耗很多计算时间,简介影响散列表的性能。

              2、散列表要尽可能的随机均匀分布。

       拓展,哈希算法:MD5SHACRC

三、散列冲突

       定义:当 key1 != key2 时,hash(key1) == hash(key2) 。

       解决办法:

              1、开放寻址法

                     定义:当出现散列冲突时,在数组中重新探测一个空闲位置,将数据插入到该位置中。

                     (1)线性探测(Linear Probing)

                                   a、冲突之后,从当前位置依次向后查找(步长为1),直到找到空闲位置将数据插入到该位置。

                                   b、上述操作之后没有发现空闲位置,则从数组的起始位置开始查找空闲位置。

                     (2)二次探测

                                   与线性探测类似,唯一的不同点,线性探测探测步长为1,而二次探测的探测步长是当前步长的2次方。

                     (3)双重散列

                                  存在多个散列函数,当其中一个函数出现了散列冲突,则使用第2个散列函数,依次类推,直到找到不存在散列冲突位置。

                     应用场景:数据量、装载因子较小。

               2、链表法(常用)

                     在散列表中每一项不再存放数据,而是存放一个链表的首地址,该链表存放与该散列值相同的数据。时间复杂度就是这些链表的长度,假设为k,时间复杂度为 O(k) 。

                     应用场景:数据量较大,存储对象较大,而且可使用红黑树代替链表。

四、装载因子(load factor)

       装载因子 = 填入表中的元素个数 / 散列表的长度 。

       装载因子越大,则空闲位置越少,冲突越多,散列表的性能就越低,时间复杂度最坏情况从 O(1) 降到 O(n) 。

       当装载因子过大时,需要动态扩容,时间复杂度为O(n)。当装载因子过小时,需要动态缩容,时间复杂度为O(n)。上述操作如果对于数据量较小时耗时不是很明显,但是对于数据量很大的情况,比如1个G,那么插值的时间就很漫长,因为要将1G的数据迁移过来。所以为了避免上述情况的发生,可以将迁移数据的情况分散在之后的每一个插入数据的过程中,这样时间复杂度就变成了O(1)。在查找的情况下,先去旧的散列表中查找,没有发现则到新的散列表中查找,同理缩容。

五、散列表碰撞攻击的原理

       对于使用链表法解决散列冲突的散列表,攻击者精心制作数据,使得这些数据全部都散列到散列表同一个位置,导致散列  表退化为链表,时间复杂度直接将为了O(n)。查询的过程中直接导致CPU资源耗尽,导致服务器无法相应其他需求。

六、设计工业级散列表的要点

       要求:

              1、支持快速的插入、删除、查找操作。

              2、内存占用合理。

              3、性能稳定,极端情况下不会退化到无法接受的程度。

       设计方向:

              1、设计合适的散列函数。

              2、定义装载因子并且设计动态扩容策略。

              3、选择合适的散列冲突的方法。

七、散列表的应用

 1、Office Word 中拼写检查功能。

       当用户拼写完一个单词之后,word会检查该单词是否是正确的,方法是开发人员将所有的单词存入内存中,存储规则是将单词做为 Key,通过相应的散列函数,计算出散列值,然后将单词报错到该散列值对应的位置中。当用户拼写完单词之后,直接在内存中查找是否存在该单词,若存在说明拼写成功,否则拼写失败。

2、假设有10万条 URL 访问日志,如何按照访问次数给 URL 排序。

       遍历10万条数据,以 URL 为 Key ,访问次数为 Value ,存入散列表中,时间复杂度为 O(n) ,之后通过相应的排序算法进行排序即可。

 

(SAW:Game Over!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值