14、python_dictionary存储hash表分析

Dictionary通过名字你就知道它是一个字典,字典的话那就是有一个关键字和值,我们通过关键字来查找对应的值。
在这里插入图片描述

Dictionary的内部存储机制:hash表
在这里插入图片描述
我们Python中的Dictionary是基于hash表,hash表的存储方式跟树有什么区别呢?首先它的存储空间还是连续的,也就是说它的读取速度会更快,因为如果用树来存储的话,它的读取速度是O(logn),而如果我们用hash表来存储的话,它的读取速度是O(1),也就是说只要经过单次操作就可以直接访问到这个值,它是怎么做到的呢?就是把每一个key都算出hash值,算出来之后我们再以hash值来插入进来,比如上图这个c我们给它算出的hash值是3,那我们就把这个c插入到索引3的位置上来。
这个时候这个速度就很快了,我们下次在查找c的时候怎么做呢?先把c转化成hash值,就得到这个元素的下标3了,我们直接通过下标3一下子就找到这个数据了,所以它的时间复杂度就变成了O(1),是快速的查找。

但是这样会出现一个问题,对于不同的关键字hash值的计算有可能会一样,不一样的可能性也很大,问题是实际上我们算出的hash值是很大的,比如算出了一个几十万大小的值,那我们能不能拿这个值直接算出下标呢,那你得准备多大的数组啊!所以你肯定要转换,在Python的源码当中它的转换方式很简单,就是做一次与操作:
在这里插入图片描述
比方说我这个数组的大小是9,那我就拿c跟9与一下,其实就把这个值的高位全去掉了,那肯定就小于9了,那我们就算出了它的位置3,比方说是1万03的,算出来之后等于3,由于它做了hash的这种与操作之后,那使得你的hash冲突的概率大大的加大了,本来两个不同的字符串生成的同样hash值的概率是很小的,但现在这样做概率就非常大,那我们如何来解决这个冲突呢?
在这里插入图片描述
假定我们的c和z生成了同样的hash值3,那我们怎么取访问呢?有多种方法,比方说大家都是3,那我在3下面创建一个链表,但这种方案使得我们的数据不连续了,因为变成链表了,我们其实相当于是一个线性表来存储的。
我们Python采用的方式是开放地址的方法,或者也称之为再散列的算法,它其实就是说,假定我们第一个c插在3这个位置,但是我这个z也是3的时候,因为发生冲突了,它会再做一次散列,它有一个二次探查的函数,二次探查的函数应该是会跳到相应的两倍的位置上去继续查找,就像2分查找一样,从两边开始继续查找,就是使得你第2次再冲突的概率降低,它通过二次探查法假设找到了,把z存在了6这个位置,这样的话下次你在找z这个值的时候,也是做一次散列,再做二次探查,找到对应的key就是6。

这样我们知道了Dictionary的存储方式内部是hash表,它会解决这种hash冲突的问题,你要考虑内部性能的时候都要考虑Python的内部机制。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值