一. 什么是字典?

字典是一系列由键(key)和值(value)配对组成的元素的集合。字典是一个可变容器模型,可以存储任意类型对象。字典实现与哈希算法密不可分(不同的Python版本,算法会不同),不了解哈希算法的童鞋可以先去了解相关知识。

二. 字典是否是有序的?

在Python3.6之前,字典是无序的,但是Python3.7+,字典是有序的。在3.6中,字典有序是一个implementation detail,在3.7才正式成为语言特性,因此3.6中无法确保100%有序。

三. 字典的查询、添加、删除的时间复杂度?

字典的查询、添加、删除的平均时间复杂度都是O(1)(为什么是平均时间复杂度,文章后面会讲解到),相比列表与元祖,性能更优。

四. 字典的实现原理?首先说说Python3.6之前的无序字典

字典底层是维护一张哈希表(见下图),我们可以把哈希表看成一个列表,哈希表中的每一个元素又存储了哈希值(hash)、键(key)、值(value)3个元素。(Python3.6之前)

enteies = [

['--', '--', '--'],

[hash, key, value],

['--', '--', '--'],

['--', '--', '--'],

[hash, key, value],

]

由上可以见哈希表的存储结构,我们也可以看出,元素之间有一些空元素,我们通过增加一个元素来讲解具体实现。计算key的hash值【hash(key)】,再和mask做与操作【mask=字典最小长度(DictMinSize) - 1】,运算后会得到一个数字【index】,这个index就是要插入的enteies哈希表中的下标位置

若index下标位置已经被占用,则会判断enteies的key是否与要插入的key是否相等

如果key相等就表示key已存在,则更新value值

如果key不相等,就表示hash冲突,则会继续向下寻找空位置,一直到找到剩余空位为止。

以上介绍了老字典的实现过程,下面我们带入具体的数值来介绍。

# 给字典添加一个值,key为hello,value为word

my_dict['hello'] = 'word'

# 假设是一个空列表,hash表初始如下

enteies = [

['--', '--', '--'],

['--', '--', '--'],

['--', '--', '--'],

['--', '--', '--'],

['--', '--', '--'],

]

hash_value = hash('hello') # 假设值为 12343543 注:以下计算值不等于实际值,仅为演示使用

index = hash_value & ( len(enteies) - 1) # 假设index值计算后等于3,具体的hash算法本文不做介绍

# 下面会将值存在enteies中

enteies = [

['--', '--', '--'],

['--', '--', '--'],

['--', '--', '--'],

[12343543, 'hello', 'word'], # index=3

['--', '--', '--'],

]

# 我们继续向字典中添加值

my_dict['color'] = 'green'

hash_value = hash('color') # 假设值为 同样为12343543

index = hash_value & ( len(enteies) - 1) # 假设index值计算后同样等于3

# 下面会将值存在enteies中

enteies = [

['--', '--', '--'],

['--', '--', '--'],

['--', '--', '--'],

[12343543, 'hello', 'word'], # 由于index=3的位置已经被占用,且key不一样,所以判定为hash冲突,继续向下寻找

[12343543, 'color', 'green'], # 找到空余位置,则保存

]

通过上面的讲解,已经了解了字典的插入的过程,可以更具此过程分析出字典查找、插入的执行过程,这里就不过多赘述。我们可以看到,不同的key计算的出的index值是不一样的,在enteies中插入的位置不一样,所以当我们遍历字典的时候,字段的顺序与我们插入的顺序是不相同的。

我们同样可以发现,enteies表是稀疏的,随着我们插入的值不同,enteies表会越来越稀疏(enteies也是一个会动态扩展长度的,每一此扩展长度,都会重新计算所有key的hash值),所以新的字典实现就随之出现。

2. Python3.7+后的新的实现方式

老字典使用一张hash,而新字典还使用了一张Indices表来辅助。下来列出新的结构:

indices = [None, None, index, None, index, None, index]

enteies = [

[hash0, key0, value0],

[hash1, key1, value1],

[hash2, key2, value2]

]

下面为具体的实现过程:计算key的hash值【hash(key)】,再和mask做与操作【mask=字典最小长度(IndicesDictMinSize) - 1】,运算后会得到一个数字【index】,这个index就是要插入的indices的下标位置(注:具体算法与Python版本相关,并不一定一样)

得到index后,会找到indices的位置,但是此位置不是存的hash值,而是存的len(enteies),表示该值在enteies中的位置

如果出现hash冲突,则处理方式与老字典处理方式类似

下面带入实际实现过程:

# 给字典添加一个值,key为hello,value为word

my_dict['hello'] = 'word'

# 假设是一个空列表,hash表初始如下

indices = [None, None, None, None, None, None]

enteies = []

hash_value = hash('hello') # 假设值为 12343543

index = hash_value & ( len(indices) - 1) # 假设index值计算后等于3,具体的hash算法本文不做介绍

# 会找到indices的index为3的位置,并插入enteies的长度

indices = [None, None, None, 0, None, None]

# 此时enteies会插入第一个元素

enteies = [

[12343543, 'hello', 'word']

]

# 我们继续向字典中添加值

my_dict['haimeimei'] = 'lihua'

hash_value = hash('haimeimei') # 假设值为 34323545

index = hash_value & ( len(indices) - 1) # 假设index值计算后同样等于 0

# 会找到indices的index为0的位置,并插入enteies的长度

indices = [1, None, None, 0, None, None]

# 此时enteies会插入第一个元素

enteies = [

[12343543, 'hello', 'word'],

[34323545, 'haimeimei', 'lihua']

]

我们在来看一下查询字典的具体过程:

# 下面是一个字典与字典的存储

more_dict = {'name': '张三', 'sex': '男', 'age': 10, 'birth': '2019-01-01'}

# 数据实际存储

indices = [None, 2, None, 0, None, None, 1, None, 3]

enteies = [

[34353243, 'name', '张三'],

[34354545, 'sex', '男'],

[23343199, 'age', 10],

[00956542, 'birth', '2019-01-01'],

]

print(more_dict['age']) # 当我们执行这句时

hash_value = hash('age') # 假设值为 23343199

index = hash_value & ( len(indices) - 1) # index = 1

entey_index = indices[1] # 数据在enteies的位置是2

value = enteies[entey_index] # 所以找到值为 enteies[2]

由上可以看出,新字典存储数据本身的enteies并不会稀疏,由indices来维护具体存储的位置,enteies中的数据是和插入的数据是一样的,所以新的字典是有序的。

上面的例子没有说明冲突的解决方案,大家可以自己思考思考。

五. 时间复杂度说明

我们在上面提到了,字典的平均时间复杂度是O(1),因为字典是通过哈希算法来实现的,哈希算法不可避免的问题就是hash冲突,Python字典发生哈希冲突时,会向下寻找空余位置,直到找到位置。如果在计算key的hash值时,如果一直找不到空余位置,则字典的时间复杂度就变成了O(n)了,所以Python的哈希算法就显得非常重要了。Python字典的哈希算法,会尽量保证哈希值计算出的index是平均分布且每一个值之间有剩余位置,例如:

[index, None, None, None, index, None, None, None]

及index尽量只为 0, 3, 5, 7类似值,保证在发生哈希冲突时,能很快的找到空余位置。

六. 字典的key能使用什么值?

Python字典的key可以使用字符串(str),整型(int),元祖(tuple)等。我们已经知道,字典是通过哈希算法来计算key的值,所以key必须为可哈希的,list不能作为字典的key,因为list是可变的及不可哈希的对象,所以不能作为字典的key。

python字典长度可变吗_Python字典dict实现原理相关推荐

  1. python中字典长度可变吗_python中列表长度可变吗

    python中列表长度可变吗?下面给大家介绍一下python中可变和不可变的类型: 可变.不可变 可变/不可变类型,指的是:内存id不变,type也不变的前提下,value是否是可变的. int()和 ...

  2. python列表长度可变吗_python中列表长度可变吗

    python中列表长度可变,可变类型指的是内存id不变,type也不变的前提下,value是否是可变的.列表和字典都是可变类型,对于可变对象,比如list,对list进行操作,list内部的内容是会变 ...

  3. python中字典长度可变吗_Python:如何给字典分配一个长度可变的列表值?

    我试图在100个2D numpy数组中定位质心,如下所示:array([[ 0.216, 0.24 , 0.244, ..., 0.679, 0.684, 0.707], [ 0.23 , 0.229 ...

  4. python字典长度可变吗_关于在Python3中:字典在迭代过程中,字典的长度是不允许改变的...

    # -*- coding: utf-8 -*- """ Created on Tue Apr 3 17:21:10 2018 @author: Lelouch_C.C & ...

  5. python字典怎么增加元素_Python字典(dict)增加元素

    Python字典(dict)增加元素 在 如果 key 不存在,那么会将 key 添加进字典,并将该 key 的值设置为 value. 字典增加元素详解 语法 dict[key] = value 参数 ...

  6. python字典里存字符_Python字典和字符串的学习

    学习Python的字典还是和oc的字典进行对比学习,首先我们来创建一个字典.根据oc中字典一样,字典是无序的,根据键来进行取值. oc: oc中的字典分为可变字典和不可变字典,在对字典进行增,删的时候 ...

  7. python字典由什么组成_python字典

    python字典: python字典是一种可变容器模型.可以储存任意类型对象. 字典由键值对组成,键值用 冒号(,)隔开,键值对之间用逗号隔开(,),整个字典包含在花括号({})中. 字典是无序的,但 ...

  8. python字典键值唯一_python字典操作详解

    python字典是一个无序.以键值对存储的数据类型,数据关联性强.唯一一个映射数据类型.键:必须是可哈希(不可变的数据类型:字符串.数字.元组.bool)值,并且是唯一的 None: none 是一个 ...

  9. python字典如何删除数据库_Python 字典删除元素clear、pop、popitem

    同其它python内建数据类型一样,字典dict也是有一些实用的操作方法.这里我们要说的是字典删除方法:clear().pop()和popitem(),这三种方法的作用不同,操作方法及返回值都不相同. ...

最新文章

  1. 【杂】突然有个想法,为了防止公司或其他,监视你的qq或微信,可以做个程序,将信息打乱,分别用qq和微信传输,然后,再还原
  2. STM32处理器存储空间布局解析
  3. [发布]Lucene索引分析工具Luke.Net 0.5升级版 (兼容Lucene.Net 2.9.4.1)
  4. php %3c php 攻击,web 攻击靶机解题过程
  5. OpenSuSe使用相关
  6. 2015年中国人才招聘趋势报告
  7. java 缓存分页_基于redis做缓存分页
  8. 问题:AmqpConnectException: java.net.ConnectException: Connection refused: connect
  9. 接口怎么获取数组底下的数组_3分钟短文 | PHP数组获取最后一个元素,10个方式中哪个有错?...
  10. PAT (Basic Level) Practice1013 数素数
  11. 图解欧洲足球五大联赛 | R爬虫可视化第五季
  12. python:基于TCP协议接收数据并解析保存至redis内存库
  13. phpmyadmin突破secure_file_priv写shell 的渗透
  14. 第三十八章 短语动词
  15. yum linux gcc安装包下载,linux下安装yum及gcc
  16. 人工智能( AI )将如何颠覆项目管理?看看这六大关键领域
  17. Mongodb使用学习笔记(三)
  18. linux文件中的^M
  19. 扫描服务器端口 PortScan Stuff
  20. 轻松可视化实现设备监控大屏效果

热门文章

  1. 小K的农场(差分约束)
  2. AndroidStudio更改默认编码(不用每次新建项目再更改编码了)
  3. 总算知道怎样从ImageMagick生成的数据转换成HICON: MagickGetImageBlob LookupIconIdFromDirectoryEx...
  4. oracle 写declare例子
  5. 小议size_t和size_type
  6. css鼠标经过table文字变色,有没有可能用css实现当table被鼠标hover的时候,table列变色?...
  7. 动态规划——最优买卖股票时机含冷冻期(Leetcode 309)
  8. CCF201912-1 报数
  9. 软件工程复习提纲——第二章
  10. php重写curl_setopt函数,PHP curl_share_setopt函数