散列查找
散列表(Hash Table)
散列表(Hash Table),又稱哈希表,是一種數據結構,特點是:數據元素的關鍵字與其存儲地址直接相關
如何建立“關鍵字”與“存儲地址”的聯系?
通過“散列函數(哈希函數)”:Addr=H(key)
若不同的關鍵字通過散列函數映射到同一個值,則稱他們為“同義詞”
通過散列函數確定的位置已經存放了其他元素,則稱這種情況為“沖突”
處理沖突的方法——拉鏈法
用拉鏈法(又稱鏈接法,鏈地址法)處理“沖突”:把所有“同義詞”存儲在一個鏈表中
散列查找
通過散列函數計算目標元素存儲地址:Addr=H(Key)
27%13=1
27的查找長度=3(對比次數)
查找目標:21
21%13=8
21的查找長度=0
查找長度——在查找運算中,需要對比關鍵字的次數稱為查找長度
平均查找長度:
第一層結點6個,對比1次有6個機會
第二層結點4個,對比2次有4次機會
第三層結點1個
第四層結點1個
“沖突”越多,查找效率越低
下面那樣情況就很好
最理想情況:散列查找時間復雜度可達到O(1)
第一個對比0次就失敗
第二個對比4次失敗。。。
裝填因子α=表中記錄數/散列表長度
裝填因子會直接影響散列表的查找效率
如何設計沖突更少的散列函數
常見的散列函數
除留余數法——H(key) = key%p
散列表表長為m,去一個不大於m但最接近或等於m的質數p
(質數:又稱素數,指除了1和此整數自身外,不能被其他自然數整除的數)
相反概念——合數
表長15,浪費了2個位置
設計目標——讓不同關鍵字沖突盡可能的少
所以要取質數
散列函數的設計要結合關鍵字分布特點來考慮,不要教條化
直接定址法——H(key) = key 或 H(key) = a*key +b
其中,a和b是常數。這種方法計算最簡單,且不會產生沖突。它適合關鍵字的分布基本連續的情況,若關鍵字分布不連續,空位較多,則會造成存儲空間的浪費
數字分析法——選取數碼分布較為均勻的若干位作為散列地址
設關鍵字是r進制數(如十進制數),而r個數碼在各位 上出現的頻率不一定相同,可能在某些位上均勻一些,每種數碼出現的機會均等;而在某些位上分布不均勻,只有某幾種數碼經常出現,此時可選取數碼分布較為均勻的若干位作為散列地址。這種方法適用於已知的關鍵字集合,若更換了關鍵字,則需要重新構造新的散列函數。
平方取中法——取關鍵字的平方值的中間幾位作為散列地址
具體取多少位要視實際情況而定。這種方法得到的散列地址與關鍵字的每位都有關系,因此使得散列地址分布比較均勻,適用於關鍵字的每位取值都夠均勻或均小於散列地址所需的位數。
假設學生不超過十萬人,可身份證平方取中間5位
處理沖突的方法——開放定址法
- 線性探測法
- 平方探測法
- 偽隨機序列法
第i次沖突
線性探測法
線性探測法——di=0,1,2,3,...m-1;即發生沖突時,每次往后探測相鄰的下一個單元是否為空。
假如要插入1
H(key) = 1%13 =1 H0=(1+d0)%16=1最開始,沖突了,所以有:
H1 = (1+d1)%16=2(發生第一次沖突計算得到的哈希地址)
如果一直沖突就一步一步的找探測值往里帶
查找操作
同義詞、非同義詞都需要被檢查
刪除操作
注意:采用“開放定址法”時,刪除節點不能簡單地將被刪結點的空間位置為空,否則將截斷在它之后增加的散列表的同義詞結點的查找路徑,可以做一個“刪除標記”,進行邏輯刪除
查找效率分析(ASL)
19%13=6——1次
14%13=1——1次
。。。
初次探測的地址H0只有可能在[0,12]
線性探測法很容易造成同義詞,非同義詞的“聚集(堆積)“現象,嚴重影響查找效率
產生原因——沖突后在探測一定是放在某個連續的位置
平方探測法
小坑:散列表長度m必須是一個可以表示成4j+3的素數,才能探測到所有位置
偽隨機序列法
其實就是di不一樣而已
處理沖突的方法——再散列法
再散列法(再哈希法):除了原始的散列函數H(key)之外,多准備幾個散列函數,當散列函數沖突時,用下一個散列函數計算一個新地址,知道不沖突為止: