《Python源码剖析》之 dict对象

Python里的dict和C++ STL的map一样,都是映射容器(key->value),但实现原理不同。由于python内部大量使用dict这种结构,效率要求很高,所以Python没有使用STL map的平衡二叉树,而采用哈希表,最低能在O(1)时间内完成搜索。
使用hash就必须解决冲突的问题,dict采用的是开放寻址法。原因我觉得是开放寻址法比拉链法能更好地利用CPU cache,cache命中率较高。
探测函数为 i = (i << 2) + i + perturb + 1; perturb每探测一次就除以2^5。

PyDictObject的存储策略

  1. 使用散列表进行存储
  2. 使用开放定址法处理冲突
    2.1 插入, 发生冲突, 通过二次探测算法, 寻找下一个位置, 直到找到可用位置, 放入(形成一条冲突探测链)
    2.2 查找, 需要遍历冲突探测链
    2.3 删除, 如果对象在探测链上, 不能直接删除, 否则会破坏整个结构(所以不是真的删)

键值PyDictEntry定义

typedef struct {
    Py_ssize_t me_hash;
    PyObject *me_key;
    PyObject *me_value;
} PyDictEntry;

说明

  1. PyDictEntry 用于存储键值对信息
  2. Py_ssize_t me_hash
    存储了me_key计算得到的hash值, 不重复计算
    这里写图片描述

补充:

每个entry有三种状态:Active, Unused, Dummy。
Unused:me_key == me_value == NULL,即未使用的空闲状态。
Active:me_key != NULL, me_value != NULL,即该entry已被占用
Dummy:me_key == dummy, me_value == NULL。
哈希探测结束的条件是探测到一个Unused的entry。但是dict操作中必定会有删除操作,如果删除时仅把Active标记成Unused,显然该entry之后的所有entry都不可能被探测到,所以引入了dummy结构。遇到dummy就说明当前entry处于空闲状态,但探测不能结束。这样就解决了删除一个entry之后探测链断裂的问题。

PyDictEntry的三个状态(图片引自-Python源码剖析)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值