Python 中的字典(dict)
dict 是如何实现的
Python中的dict是通过散列表实现的。
那么什么是散列表呢?
散列表其实就是一个稀疏的数组(总是有空白元素的数组称为稀疏数组)。散列表中的单元通常称为表元。在dict的散列表中,每个键值对都占有一个表元,每个表元都有两个部分,一个是对键的引用,另一个是对值的引用。因为所有的表元的大小一致,所以可以通过偏移量来读取某个表元。
因为python会设法保证大概有三分之一的表元是空的,所以快要达到这个阈值时,原有的散列表会被复制到一个更大的空间。
python是如何通过key取出其值的呢?
为了获取my_dict[search_key]背后的值,python首先调用hash(search_key)来计算search_key的散列值,把这个值最低的几位数字当作偏移量,在散列表中查找表元(具体取几位,得看当前散列表的大小)。若找到表元为空,则抛出KeyError异常。若不是为空,则表元中会有一对found_key:found_value。这个时候,python会检验search_key == found_key是否为真,如果它们相等,就会返回found_value。
如果search_key和found_key不匹配的话,这个情况就称为散列冲突。发生这种情况是因为,散列表所做的其实是把随机的元素映射到只有几位的数字上,而散列表本身的索引又只依赖于这数字的一部分。为了解决散列冲突,算法会在散列值中另取几位,然后用特殊的方法处理,把新的数字在作为索引来寻找表元。若这次找到的表元是空,返回KeyError;若不为空,且键匹配则返回值,不匹配,则又出现散列冲突,重复上面的步骤。
dict中的添加新元素和更新元素
dict中添加新元素和更新新元素操作和取值类型,只不过是,对于添加新元素时,发现空表元的时候,放入一个元素,对于更新元素,在找到对应表元时,原表中的值会被替换成新的值。
另外在插入新值时,python会按照散列表的拥挤程度来决定是否重新分配内存为它扩容。如果增加了散列表的大小,那散列值所占的位数和用作索引的位数都会随之增加,为的是减少发生散列冲突的概率
优缺点
由于dict是通过散列表实现的,而散列表又是稀疏的,所以导致它在空间上效率低下。但是它提供了无视数据量大小的快速访问------只要字典被装在内存中。dict的实现就是典形的空间换时间。