[Python] 字典及底层哈希

本文介绍了Python字典的底层实现原理,基于哈希表的数据结构,详细阐述了哈希冲突的处理方法(开放寻址法),并讨论了哈希表在查找效率上的优势。还探讨了Python字典的创建、初始化、获取、更新、添加和删除等操作,以及不可变对象作为键的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Python内置了字典dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。

Python的dict采用了哈希表实现,最快能在O(1)时间内完成搜索。java的HashMap也是采用了哈希表实现。
不同之处是,dict在发生哈希冲突的时候采用了开放寻址法,而HashMap采用了链接法。

1.哈希表

在这里插入图片描述

直接寻址表:将 key 为 k 的元素,存放在索引为 k 的位置上
哈希表 :将 key 为 k 的元素,存放在索引为 h(k) 的位置上。

哈希表(Hash Table,又称为散列表)是一种线性表的存储结构。由一个直接寻址表 T (假设大小为m) 和一个哈希函数 h(k) 组成。对于任意可哈希对象,通过哈希函数(一般先进行哈希计算,然后对结果进行取余运算),将该对象映射为寻址表的索引 [0,1,2,…m-1],然后在该索引所对应的空间 T[0,1,2,…,m-1] 进行变量的存储/读取等操作。如下图所示。
在这里插入图片描述
Python 字典的底层实现是哈希表。调用内部的哈希函数,将键(Key)作为参数进行转换(哈希运算+取余运算),得到一个唯一的地址(地址的索引),然后将值(Value)存放到对应地址中(给相同的键赋值会直接覆盖原值,因为相同的键转换后的地址是一样的)。

例1:
在这里插入图片描述
例2:

Python中的字典: a = {‘name’: ‘Alex’, ‘age’: 18, ‘gender’: ‘Man’}

使用哈希表存储字典,通过哈希函数将字典的键映射为下标。
假设h(‘name’) = 3, h(‘age’) = 1, h(‘gender’)= 4,则哈希表存储为[None, 18, None, ’Alex’, ‘Man’]

注:键(Key)必须是可哈希的,即,通过哈希函数可为此键计算出唯一地址。

对于 Python 来说,变量,列表、字典、集合这些都是可变的,所以都不能做为键(Key)来使用。因为元祖里边可以存放列表这类可变因素,所以如果实在想拿元祖当字典的键(Key),那必须对元祖做限制:元组中只包括像数字和字符串这样的不可变元素时,才可以作为字典中有效的键(Key)。另外还需要注意的一点是,Python 的哈希算法对相同的值计算得到的结果是一样的,也就是说 12315 和 12315.0 的值相同,他们被认为是相同的键(Key)。

2.Python字典如何运用哈希表

插入: 对键进行哈希和取余运算,得到一个哈希表的索引,如果该索引所对应的表地址空间为空,将键值对存入该地址空间;
查询/更新: 对健进行哈希和取余运算,得到一个哈希表的索引,如果该索引所对应的地址空间中健与要查询/更新的健一致,那么就将该键值对取出来 / 更新该键所对应的值;
扩容: 字典初始化的时候,会对应初始化一个有k个空间的表,等空间不够用的时候,系统就会自动扩容,这时候会对已经存在的键值对 重新进行哈希取余运算(重新进行插入操作)保存到其它位置;

3.哈希冲突

由于哈希表的大小是有限的,而要存储的值的总数量是无限的,因此对于任何哈希函数,都会出现两个不同元素映射到同一个位置上的情况,这种情况叫做哈希冲突。字典使用了开放寻址法来解决冲突。

比如: h ( k ) = k m o d 7 , h ( 0 ) = h ( 7 ) = h ( 14 ) = . . . h(k)=k mod 7, h(0)=h(7)=h(14)=... h(k)=kmod7,h(0)=h(7)=h(14)=...

开放寻址法:如果哈希函数返回的位置已经有值,则可以探查新的空位置来存储这个值。

线性探查:如果位置i被占用,则探查 i + 1 i+1 i+1,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值