說說Python中字典和雜湊表,雜湊衝突的解決原理

2021-09-24 11:19:47 字數 1578 閱讀 1128

雜湊表

python 用雜湊表來實現 dict。雜湊表其實是乙個稀疏陣列(總是有空白元素的陣列稱為稀疏陣列)。在一般書中,雜湊表裡的單元通常叫做表元(bucket)。在 dict 的雜湊表當中,每個鍵值對都占用乙個表元,每個表元都有兩個部分,乙個是對鍵的引用,乙個是對值的引用。因為每個表元的大小一致,所以可以通過偏移量來讀取某個表元。

python 會設法保證大概還有三分之一的表元是空的,當快要達到這個閥值的時候,會進行擴容,將原雜湊表複製到乙個更大的雜湊表裡。

如果要把乙個物件放入到雜湊表裡,就先要計算這個元素鍵的雜湊值。這就要求鍵(key)必須是可雜湊的。

乙個可雜湊的物件必須滿足以下條件:

支援 hash() 函式,並且通過hash() 方法所得到的雜湊值是不變的。

支援通過eq() 方法來檢測相等性。

若 a == b 為真,則 hash(a) == hash(b) 也為真。

雜湊表的演算法:

為了獲取鍵 search_key 所對應的值 search_value,python 會首先呼叫 hash(search_key) 計算 search_key 的雜湊值,把這個值最低的幾位數字當作偏移量,在雜湊表裡查詢表元(具體取幾位,得看當前雜湊表的大小)。若找到的表元是空的,則丟擲 keyerror 異常;若不為空,則表元裡會有一對 found_key:found_value,檢驗 search_key 和 found_key 是否相等,若相等,則返回 found_value。若不相等,這種情況稱為雜湊衝突

為了解決雜湊衝突,演算法會在雜湊值中另外再取幾位,然後用特殊的方法處理一下,把得到的新數值作為偏移量在雜湊表中查詢表元,若找到的表元是空的,則同樣丟擲 keyerror 異常;若非空,則比較鍵是否一致,一致則返回對應的值;若又發現雜湊衝突,則重複以上步驟。

新增新元素跟上面的過程幾乎一樣,只不過在發現空表元的時候會放入這個新元素,不為空則為雜湊衝突,繼續查詢。

為什麼字典是無序的

當往 dict 裡新增新元素並且發生了雜湊衝突的時候,新元素可能會被安排存放到另乙個位置。於是就會發生下面的情況:dict([key1, value1], [key2, value2]) 和 dict([key2, value2], [key1, value1]) 兩個字典,在進行比較的時候是相等的,但如果 key1 和 key2 雜湊衝突,則這兩個鍵在字典裡的順序是不一樣的(因為新增的順序不一樣,先新增的先佔據第一次雜湊值的位置,後新增的)。

無論何時,往 dict 裡新增新的鍵,python 解析器都可能做出為字典擴容的決定。擴容導致的結果就是要新建乙個更大的雜湊表,並把字典裡已有的元素新增到新的雜湊表裡。這個過程中可能發生新的雜湊衝突,導致新雜湊表中鍵的次序變化。

如果在迭代乙個字典的同時往裡面新增新的鍵,會發生什麼?不湊巧擴容了,不湊巧鍵的次序變了,然後就 orz 了。

總結雜湊表是乙個在時間和空間上做出權衡的經典例子。如果沒有空間(記憶體)的限制,那麼可以直接將鍵作為陣列的索引。那麼所有的查詢時間複雜度為 o(1);如果沒有時間的限制,那麼可以直接用陣列,這樣只需要很少的記憶體。

字典和雜湊表

在字典 或對映 中,用 鍵 值 對的形式來儲存資料。如果item變數是乙個物件的話,需要實現tostring方法,否則會導致出現異常的輸出結果,如 object object function defaulttostring item else if item undefined else if t...

Python 字典 集合 and 雜湊表

資料結構 字典與集合的資料結構都以雜湊表的形式進行。雜湊表的單元通常叫做表元。表元由兩部分組成,乙個是對鍵的引用,乙個是對值的引用。每個表元的大小是相同的。所以可以通過偏移量直接計算找到對應表元,從而根據引用找到相應的鍵以及與之對應的值。順序可能會打亂 以雜湊表實現,那麼為了減少衝突,要時刻保持 1...

流暢的python 字典中的雜湊表

字典中的雜湊表其實就是稀疏陣列 總會有一些元素是空白的陣列 雜湊表中的單元叫 表元,在構建字典時會有產生兩個表元,乙個用來標記健,乙個用來標記值,因為兩個表元的長度都是相等的,所以可以通過表元的偏移量來查詢字典。python中最具有效率的內建資料型別就是字典和集合,這兩種都是通過雜湊表來實現的。為了...