python中列表与字典的底层实现

本文主要围绕效率开始说起

 

常见算法效率复杂度

O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)

 

python列表内置操作方法的复杂度如下

python中列表与字典的底层实现_第1张图片

 

常见的顺序表存储方式如下,python则采用的是分离式结构,表头只存储最大容量值,元素个数和存储区的物理地址,

 

python中列表与字典的底层实现_第2张图片

存储区的结构示意图,其中存储区域涉及的主要知识点为扩容问题,python采用的是容量加倍的方式,但当元素超过50000个时,其便会改变策略,以避免不必要的浪费

 

扩充的两种策略

  • 每次扩充增加固定数目的存储位置,如每次扩充增加10个元素位置,这种策略可称为线性增长
    • 特点:节省空间,但是扩充操作频繁,操作次数多。
  • 每次扩充容量加倍,如每次扩充增加一倍存储空间。
    • 特点:减少了扩充操作的执行次数,但可能会浪费空间资源。以空间换时间,推荐的方式。

 

python中列表与字典的底层实现_第3张图片

 

Python标准类型list就是一种元素个数可变的线性表,可以加入和删除元素,并在各种操作中维持已有元素的顺序(即保序),而且还具有以下行为特征:

  • 基于下标(位置)的高效元素访问和更新,时间复杂度应该是O(1);

    为满足该特征,应该采用顺序表技术,表中元素保存在一块连续的存储区中。

  • 允许任意加入元素,而且在不断加入元素的过程中,表对象的标识(函数id得到的值)不变。

    为满足该特征,就必须能更换元素存储区,并且为保证更换存储区时list对象的标识id不变,只能采用分离式实现技术。

在Python的官方实现中,list就是一种采用分离式技术实现的动态顺序表。这就是为什么用list.append(x) (或 list.insert(len(list), x),即尾部插入)比在指定位置插入元素效率高的原因。

优质链接参考:https://cloud.tencent.com/developer/article/1489092

https://www.jianshu.com/p/cd75475168ae

 

 

 

dict分析

python中列表与字典的底层实现_第4张图片

字典是通过散列表或说哈希表实现的。字典也被称为关联数组,还称为哈希数组等。也就是说,字典也是一个数组,但数组的索引是键经过哈希函数处理后得到的散列值。哈希函数的目的是使键均匀地分布在数组中,并且可以在内存中以O(1)的时间复杂度进行寻址,从而实现快速查找和修改。哈希表中哈希函数的设计困难在于将数据均匀分布在哈希表中,从而尽量减少哈希碰撞和冲突。由于不同的键可能具有相同的哈希值,即可能出现冲突,高级的哈希函数能够使冲突数目最小化

 

什么是hash冲突?

假设hash表的大小为9(即有9个槽),现在要把一串数据存到表里:5,28,19,15,20,33,12,17,10

简单计算一下:hash(5)=5, 所以数据5应该放在hash表的第5个槽里;hash(28)=1,所以数据28应该放在hash表的第1个槽里;hash(19)=1,也就是说,数据19也应该放在hash表的第1个槽里——于是就造成了碰撞(也称为冲突,collision

 

解决hash冲突,python采用开放地址法,java和redis都采用链接方法

关于开放地址法与链接优缺点https://zhuanlan.zhihu.com/p/33496977

 

原文链接:https://blog.csdn.net/answer3lin/article/details/84523332

开放地址法的具体实现

python中列表与字典的底层实现_第5张图片

python中列表与字典的底层实现_第6张图片


 

 

 

 

 

 

 

 

 

你可能感兴趣的:(python中列表与字典的底层实现)