Python字典的實現原理


以下是自己的學習記錄,算是一個總結。

接下來會依次對下面問題做一個解答:
    1. Python的dict和set為什么是無序的?
    2. 為什么不是所有的python對象都可以用作dict的鍵和set中的元素

要弄懂上面的問題,我們首先要了解Python內部是如何實現dict和set類型的。我們先來看看dict的內部結構,dict其實本質上是一個散列表(散列表即總有空白元素的數組,Python會保證至少有三分之一的數組元素是空的),dict的每個鍵都占用一個表元,而一個表元中又分為兩個部分,分別是對鍵的引用和對值的引用。當我們存放一個對象的時候,首先會要計算這個元素的散列值,python中使用hash()方法來實現的,這也就回答了第二個問題,因為不是所有的python對象都可以使用hash來獲取散列值,獲取不到散列值也就不可能存放到dict中,所以只有可hash的對象才能夠作為dict的鍵。值得注意的是內置的hash方法可以用於所有的內置類型對象的,所有用戶自定義的對象默認都是可以作為鍵的,因為自定義對象的散列值是通過id()來獲取的。例如:

class T(object):
    pass


t = T()

print(id(t))
d = {t: 1}
print(d)

###  2133693018240
###  {<__main__.T object at 0x000001F0CA03B080>: 1}

現在假設我們已經獲取到了元素的散列值,接下來就該計算應當存放位置了,將散列值對數組長度進行取余,得到的結果就是存放位置的索引了。但是不同的key可能會得到相同的散列值,也就是哈希沖突的問題,python內部是使用開放尋址的方法來解決的,開放尋址法就不在此詳細說了。關於為什么dict是無序的,這個是因為python內部會保證散列表至少有三分之一的位置為空,當我們增加元素的時候,python有可能會對散列表進行擴容,具體操作就是重新開辟一塊更大的空間,將原有的元素添加到新表里面,這個過程中可能又會發生新的散列沖突,導致新的散列表中的鍵的次序發生變化。當然呢如果想要保存順序也可以使用OrderedDict來處理

 

dict操作的時間復雜度:

操作 操作說明 時間復雜度
copy 復制 O(n)
get(value) 獲取 O(1)
set(value) 修改 O(1)
delete(value) 刪除 O(1)
search(in) 字典搜索 O(1)
iterration 字典迭代 O(n)

set集合和dict一樣也是基於散列表的,只是他的表元只包含值的引用而沒有對鍵的引用,其他的和dict基本上是一致的,所以在此就不再多說了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM