python—dict使用总结和思考

在python中,dict和list是两种常见数据类型,dict用于内容空间足够、依据值快速检索的场景,list用于内存空间有限、根据下标快速检索的场景。

使用场景:

List:类似于C中的array数组,数据存储在一段连续内存空间中;根据值查询时候,需要从头到尾逐一遍历,复杂度O(N)。根据索引index查询时候,直接做索引index偏移,复杂度O(1)。

Dict:在python底层实现为可变哈希表,本质也可以看做List,区别在于List的存放地址按照先后顺序得到,而Dict的存放地址需要根据哈希函数+哈希碰撞得到。

 

原理说明:

List:(1)python底层实现为一个长度可变的数组,数组中存放的是每个元素的索引index,根据索引查询不受List长度和所存放的元素影响。(2)对于频繁的append和insert操作,CPython会额外进行一些技巧,比如频繁append时候会额外分配比实际需要大一些的空间,避免频繁开辟空间。

Dict:(1)可变哈希表,key通过hash函数映射为哈希值,哈希值进一步映射到哈希表大小size的位置index上,value的地址就存放在index所对应的空间上。(2)说明:Dict中的key必须是可哈希(python中不可变数据都是可哈希的,而可变数据则不可哈希),原因是一旦key可变,key发生变化之后,则无法根据变化后的新key值查询到value,也无法查询到旧key值对应的value值。(3)哈希表的内容:哈希表一行记录2个数据:key的引用和value的引用。(4)python实现,将key哈希得到哈希值之后,只是用哈希值末尾几位计算哈希表存放位置,在哈希表较拥挤触发哈希扩容之后,会增大哈希值的末尾几位。(5)cpython的哈希函数为:hash("key值")&*(2^k-1)【等价于hash("key值")%(k+1)】

 

注意点:

1、使用List,根据value检索会是O(N)时间复杂度,建议下标index检索数据。

2、使用Dict,根据key检索value虽然会很快,但会占用更多空间,因为哈希表会至少空出1/3的空间,insert操作会在哈希表大小达到2/3触发扩容操作。

3、底层数据存放时候,List是按操作先后顺序存放,而Dict会按照key的哈希值存放,实际value会无序存放。

4、数据要想能哈希,需要能调用python内置的hash()方法和__eq__()【数值相等性检测】方法。

 

常见问题(个人理解,欢迎大神指出错误):

1、当初始化一个非空dict时,python底层进行了哪些过程?

答:

step1:开辟一段连续的内存空间用于哈希表操作。

step2:计算各个key的哈希值,再根据哈希值计算value在哈希表中的存放位置,中间可能会遇到哈希冲突和哈希表扩容。

step3:为value开辟内容空间,将具体值存放进去。

step4:将value值所在内存空间的地址存放到哈希表的相应位置空间上。

step5:将哈希表所在内存空间的地址存放到字段变量所在的空间上。

 

2、为什么说Dict的元素是无序存放?

答:key的哈希计算的结果无序,哈希冲突导致无序,哈希表扩容重新哈希导致无序。

 

3、dict进行insert时候,如何解决哈希冲突?

答:哈希冲突(碰撞)可以采用线性寻址以及其他的非线性寻址解决(伪随机探测)。

 

4、dict在扩容时候,如何解决扩容操作?

答:哈希表始终维持1/3的空表元(哈希表的一行称为表元,也叫做bucket),在哈希表的表元数目达到2/3时候,会启动自动扩容操作:分配一块更大的连续内存空间用以存放哈希表,而旧哈希表数据经重新哈希(在冲突或者碰撞中使用某种hash函数重新)会存到新哈希表中。

 

5、什么是哈希?

答:

(1)哈希是一种数据(信息)压缩编码技术,将数据(信息)以统一的格式进行编码为“指纹”(哈希值,哈希值通常比原始值长度更短),这种指纹可以对原始数据(信息)隐藏和保护,比如不论数字还是字符串。哈希之后得到的哈希值都是数字。

(2)常用哈希函数形式:hash("key值") % k,其中k是哈希表的长度,哈希之后的结果是0到k-1之间的数值。

(3)目的:通过哈希操作将原始值统一编码+打乱,尽可能均匀映射、分布到另一个区间上。

 

6、什么是哈希表?
答:哈希表本质是一个数组,内存空间连续分配,而且可以适时动态分配。数据元素经哈希函数计算(一般是模运算后取余数)后得到哈希表的某个bucket位置,数据原始的地址便可以存放到指定位置,遇到冲突即通过哈希冲突重新计算位置;当哈希表表元数目达到临界值时,则进行扩容处理。

 

7、数据存放在list或者dict中时候,实际数据是如何存放的?

答:不管是List还是Dict,数据值本身都是单独分配空间存放,数据值所在空间地址则存放到List或者Dict相应的地址空间。

 

8、为什么dict的key需要不可变?

答:一旦key可变,当key变化之后,key的哈希值也会变化,这时使用key变量则无法获取到value,同时因为key变化了,也无法知晓旧的哈希值。

 

8、哈希表扩容时候,如何合理扩容?

参考:链接4

 

 

更多学习笔记可以关注我的微信公众号「kelly学挖掘」,欢迎交流。

-- over --

 

参考资料:

1、https://docs.python.org/3.5/faq/design.html#how-are-lists-implemented

2、https://docs.python.org/3.5/library/functions.html#hash

3、https://blog.csdn.net/lovebaby859450415/article/details/79620715

4、https://blog.csdn.net/qq_27576655/article/details/85949183

5、https://www.jianshu.com/p/68db5cff4872

6、https://blog.csdn.net/qq_42815145/article/details/91353624

7、https://www.cnblogs.com/gl1573/archive/2018/10/09/9758941.html

8、https://www.cnblogs.com/yc3110/p/10451431.html

9、https://blog.csdn.net/junjunba2689/article/details/82814166【仔细看看】

10、https://blog.csdn.net/siyue0211/article/details/80560783?utm_source=copy

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值