当前位置: 首页 > news >正文

python字典为什么至少需要哈希表的三分之一的行留空

Python 字典(dict)的底层实现是基于 哈希表 的。在哈希表中,哈希冲突性能优化 是非常重要的问题。为了保证字典在插入、查找、删除操作时的高效性,Python 设计了一个规则,即字典的哈希表中至少要有三分之一的空间是空的。这背后主要有以下几个原因:

1. 避免哈希冲突

哈希表的工作原理是通过哈希函数将键映射到表中的某个位置(槽位)。理想情况下,不同的键应该映射到不同的槽位。然而,在实际中,哈希函数可能会将多个不同的键映射到同一个槽位,这就是所谓的 哈希冲突

  • 当哈希表中槽位过于拥挤时,哈希冲突的概率大大增加。
  • 每次发生冲突时,Python 会采用开放寻址法(open addressing),也就是通过某种算法查找下一个空闲的槽位。
  • 如果表中大多数槽位都被占用了,那么寻找空槽位的操作会变得非常耗时,从而影响字典的性能。

通过保留一定的空槽位,可以大幅减少冲突次数,从而提高查找和插入的速度。

2. 提升查找和插入的效率

字典操作(如查找、插入和删除)的时间复杂度期望为 O(1)。这是因为哈希表的设计可以让键在常数时间内被映射到一个槽位。然而,当哈希表接近满时:

  • 每次查找空闲槽位的平均时间会变长(因为需要线性探测或某种探测方式)。
  • 插入新键的时间也会增加,因为哈希冲突的处理会耗费额外时间。

为了避免哈希表在使用时变得拥挤,Python 保证哈希表的负载因子不会超过 2/3,这就意味着至少三分之一的槽位是空的,从而保证字典操作的高效性。

3. 降低表的扩展频率

哈希表需要扩展时,所有现有的键值对必须重新计算哈希并放入新的、更大的表中。这一过程称为 rehashing,它是一个相对昂贵的操作。

如果哈希表填满得过快(例如槽位利用率接近 100%),则系统需要频繁扩展哈希表。为了降低扩展的频率,Python 设计哈希表时预留了一定的空间,避免过早触发扩展。

因此,通过保持哈希表中至少三分之一的行为空的,Python 减少了哈希表的扩展次数,避免频繁 rehashing 操作。

4. 内存与性能的权衡

虽然预留哈希表的空间会占用额外的内存,但这种内存的额外开销是可以接受的,尤其是在现代计算机的内存资源通常比较充足的情况下。相对地,保证字典操作的高效性(如查找和插入的 O(1) 复杂度)对于性能至关重要。

5. 类似的设计思想

在 Python 中,除了字典(dict)使用了空间换时间的设计思想,许多其他的内建数据结构和模块也使用了类似的设计思路,以提高操作效率。下面是一些使用了类似思想的例子:

列表(list)动态扩展
Python 中的列表(list)是动态数组,底层实现类似于 C 语言中的动态数组。Python 为了提高列表的操作效率,特别是在列表扩展时,采取了一种预分配空间的策略。

设计思想
当列表需要扩展时,Python 并不会每次都精确地增加所需的内存,而是会预分配额外的空间。这样,当你不断向列表中追加元素时,不需要频繁重新分配内存,从而提高性能。

具体实现
列表一旦达到容量上限并需要扩展,Python 会分配一个比当前容量更大的新数组,通常是按一定倍数增长,然后将现有的元素复制过去。
这种策略避免了在每次插入新元素时都进行重新分配和复制,减少了重新分配的次数。
优点
提升 append 操作的效率,平均时间复杂度为 O(1),虽然偶尔会有较慢的重新分配和复制操作,但通过预分配可以使这些开销摊薄。
内存和性能权衡
虽然预分配多余的空间会浪费一些内存,但这换来了性能的提升,特别是在大量追加操作的情况下。

集合(set)和冻结集合(frozenset)
集合(set)和字典类似,底层也是基于哈希表实现的,因此它们也采用了类似字典的设计,至少预留三分之一的空间以减少哈希冲突。

设计思想
集合中的元素是无序且唯一的,当插入、删除或查找元素时,Python 使用哈希表来进行这些操作。
通过预留空间和处理冲突的方法,set 的查找、插入和删除操作的时间复杂度为 O(1),这与字典的性能非常接近。


http://www.mrgr.cn/news/42704.html

相关文章:

  • linux常用的命令
  • 用Python和OpenCV实现人脸识别:构建智能识别系统
  • C++:const成员
  • 力扣 简单 100.相同的树
  • C语言第15课—数据在内存中的存储
  • 基于Zynq SDIO WiFi移植一(支持2.4/5G)
  • mysql设置表的某一个字段每天定时清零
  • 【数据结构】链表-1
  • C++基础(7)——STL简介及string类
  • js进阶——深入解析JavaScript中的URLSearchParams
  • 文心一言 VS 讯飞星火 VS chatgpt (361)-- 算法导论24.3 3题
  • java入门基础(一篇搞懂)
  • 红日靶机(三)笔记
  • 神经网络激活函数之前的加权求和 | 矩阵相乘运算法则(清晰版)
  • Python : 类变量、静态方法、类方法
  • 初识Linux · 自主Shell编写
  • 基础算法之双指针--Java实现(上)--LeetCode题解:移动零-复写零-快乐数-盛最多的水
  • win11远程连接MySQL(linux版),不需安装docker容器
  • 探索TCP协议的奥秘:Python中的网络通信
  • Python+Matplotlib-高等数学上-P7-例如部分可视化