数据结构与算法Python版 04 数构之哈希篇

本文详细介绍了哈希表(散列表)的概念、数据存储、哈希函数以及解决冲突的方法,包括开放定址法、再哈希法、链地址法等。并探讨了Python中dict的实现,强调了key的唯一性和不可变性,以及动态扩容的策略。
摘要由CSDN通过智能技术生成

Hash Table

散列表(hash table)也被称为哈希表,它是一种根据键(key)来存储值(value)的特殊线性结构。

常用于迅速的无序单点查找,其查找速度可达到常数级别的O(1)。

散列表数据存储的具体思路如下:

  • 每个value在放入数组存储之前会先对key进行计算
  • 根据key计算出一个重复率极低的指纹
  • 根据这个指纹将value放入到数组的相应槽位中

同时查找的时候也将经历同样的步骤,以便能快速的通过key查出想要的value。

这一存储、查找的过程也被称为hash存储、hash查找。

如图所示:

image-20210614204610051

我们注意观察,其实散列表中的每一个槽位不一定都会被占据,它是一种稀疏的数组结构,即有许多的空位,并不像list那种顺序存放的结构一样必须密不可分,这就导致了散列表无法通过index来进行value的操作。

散列表在Python中应用非常广泛,如dict底层就是散列表实现,而dict也是经历了上述步骤才将key-value进行存入的,后面会进行介绍。

名词释义

在学习Hash篇之前,介绍几个基本的相关名词:

  • 散列表(hash table):本身是一个普通的数组,初始状态全是空的
  • 槽位(slot、bucket):散列表中value的存储位置,用来保存被存入value的地方,每一个槽位都有唯一的编号
  • 哈希函数(hash function):如图所示,它会根据key计算应当将被存入的value放入那一个槽位
  • 哈希值(hash value):哈希函数的返回值,也就是对数据项存放位置的结算结果

还有2个比较专业性的词汇:

  • 散列冲突:打个比方,k1经过hash函数的计算,将v1存在了1号槽位上,而k22也经过了hash函数的计算,发现v2也应该存在1号槽位上。

    现在这种情况就发生了散列冲突,v2会顶替v1的位置进行存放,原本1号槽位的存放数据项会变为v2。

  • 负载因子:说白了就说这个散列表存放了多少数据项,如11个槽位的一个散列表,存放了6个数据项,那么该散列表的负载因子就是6/11

哈希函数

如何通过key计算出value所需要插入的槽位这就是哈希函数所需要思考的问题。

求余哈希法

如果我们的key是一串电话号码,或者身份证号,如436-555-4601:

  • 取出数字,并将它们分成2位数(43,65,55,46,01)
  • 对它们进行相加,得到结果为210
  • 假设散列表共有11个槽位,现在使用210对11求余数,结果为1

那么这个key所对应的value就应当插入散列表中的1号槽位

平方取中法

平方取中法如下,现在我们的key是96:

  • 先计算它的平方值:96^2
  • 平方值为9216
  • 取出中间的数字:21
  • 假设散列表共有11个槽位,现在使用21对11求余数,结果为10

那么这个key所对应的value就应当插入散列表中的10号槽位

字符串求值

上面举例的key都是int类型,如果是str类型该怎么做?

我们可以遍历这个str类型的key,并且通过内置函数ord()来将它字符转换为int类型:

>>> k = "hello"
>>> i = 0
>>> for char in k:
	i += ord(char)
>>> i
532

然后再将其对散列表长度求余,假设散列表共有11个槽位,现在使用532对11求余数,结果为4

那么这个key所对应的value就应当插入散列表中的4号槽位。

字符串问题

如果单纯的按照上面的方式去做,那么一个字符完全相同但字符位置不同的key计算的hash

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值