python字典核心底层原理

字典核心底层原理

字典对象的核心是散列表,散列表是一个稀疏数组(总有空白元素的数组)数组的

每个单元叫做bucket。每个bucket由两部分:一个是键对象的引用,一个是值对象的引用

由于,所有bucket结构和大小一致,我们可以通过偏移量来读取指定bucket

字典元素的访问也可以通过索引来访问,也就是字典元素包括三个方面,索引,键对象,值对
象,它通过索引来确定键对象的位置

假设我们的字典创建完成之后,数组长度是8,首先我们列出0-7的二进制编码,前面补0成为
三位数

  0	 	0	  变成      	0		000  	前面补0凑生三位
    1		1			1		001
    2		10			2		010
    3		11			3		011
    4		100			4		100
    5		101			5		101
    6		110			6		110
    7		111			7		111

我们创建一个数组,然后计算键“name”的散列值,可以通过hash()来计算,bin()是
将里面的数值转化为二进制编码

>>> a = {"name":"www","age":18}
>>> hash("name")
-2129792525715549463
>>> bin(hash("name"))
'-0b1110110001110100010110000010010011100100011101010110100010111'

像我们取得字典长度为8,它的填入方式是计算处散列值的最右边的三位数值的偏移量

及(111),十进制是3,我们查看偏移量为3对应的bucket是否为空,如果为空,则将键值
放进去,如果不为空则依次取右边三位作为偏移量,及010,十进制是2,查看偏移量是否为
空,直到找到我胃口的bucket将键值放进去,如果八个位置都满了,他会自动扩容到十六进制,一般满三分之二后就会自动扩容

8		1000		9		1001		10		1010		11		1011
12		1100		13		1101		14		1110		15		1111

关于进制问题的个人看法,我们发现为什么八进制,十六进制,三十二进制这些进制比较常用

也是有些原因的,像8进制0-7,计算机一般从0开始计数,7的二进制是111 15的二进制是

1111,如果是十进制,我们发现它正好卡在三位和四位二进制之间,如果我们安四个二进制

一读取,那么出现大于10小于15的数值如何判断,因为他们也是四位二进制,也就是说计算

机想要进行十进制转换,在大于7,小于10这部分还要加一个判断语句,这也就是为什么计算

机常用二进制,八进制,十六进制的原因了,计算机是二进制的,转化为八进制读取二进制前

三位数,十六进制读取前四位数,这种转化是非常简单快速的,如果转化为其他进制还需要运

行某些判断语句

根据键查找“键值对”的底层过程

我们我们访问字典元素的时候就是通过“键对象”查找到“键值对”,从而找到值对象

根据键对象查找的方法和填入的方法差不多,都是要计算“键对象”的散列值,依次取不同二
十的二进制散列值,假设长度为8,我们就拿出计算的散列值的最右边的3位二进制数字作为
偏移量,这中间会有一个判断,因为我们是按三位数字的取值方法,所以会有重复的可能,它

在找到对应的偏移量之后会有一个整体判断的环节,如果整体不同,则查找下三位的二进制数

如果“值对象”为空,则返回None。如果取完所有三列值仍然没有找到,那么也会返回
None

用法总结:
键必须可散列
数字,字符串,元组都是可散列的
自定义对象需要支持下面三点
支持hash()函数
支持通过__eq__()方法检查相同性
若a ==b为真,则hash(a)==hash(b)也为真

发布了68 篇原创文章 · 获赞 30 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43254438/article/details/84376677