**引入:**咱們在學習數組的時候,使用數組元素的下標值便可訪問到該元素,所花費的時間是O(1),與數組元素的個數n沒有關係,這就是哈希方法的核心思想。golang
**哈希方法:**以關鍵值K爲自變量,經過必定的函數關係h(K)(哈希函數)計算出對應的函數值,把這個值解釋爲結點的存儲地址,將結點的關鍵碼(key)和屬性數據(value)一塊兒存入此存儲單元中。檢索時,用一樣的函數計算出地址,找到對應的數據。算法
**哈希表:**按哈希存儲方式構造的存儲結構稱爲哈希表(hash table)數組
**舉例:**已知線性表關鍵碼值集合爲S={and, begin, do, else, for,golang},假設哈希函數是關鍵碼K的第一個字母在字母表中的序號,哪麼能夠創建以下的哈希表:數據結構
固然這個例子特別簡單,細心的同窗很快就發現了二個問題:app
其實這就是接下來要談到的哈希函數的選擇和衝突解決策略。函數
哈希方法的核心就是哈希函數的選擇,理想的哈希函數應該使得結點「分佈均勻」,且衝突少學習
爲了簡單起見,如下的哈希函數咱們假設關鍵值都是整數(若是不是整數,哪也有特定的方法能夠把它轉換爲整數,畢竟在計算機世界裏,任何東西都是01組成的串)優化
除餘法:spa
關鍵值碼k除以M(每每取哈希表的長度),並取餘數做爲哈希地址。blog
乘餘取整法
先讓關鍵碼k乘上一個常數A(0<A<1),提取乘積的小數部分。而後,再用整數n乘以這個值,對結果向下取整,將其做爲哈希的地址。
有許多種哈希函數能夠選擇,每種都有其適用的場景,可是做爲軟件開發工程師,咱們只要理解它的思想就能夠,至於什麼場景選擇什麼哈希函數,哪大機率是數學家應該研究的問題。
優秀的哈希函數能夠儘量的避免產生衝突,可是衝突的產生是不可避免地,這就是接下來要談到的衝突解決策略
衝突解決技術能夠分爲兩類,拉鍊法和開地址法,這兩種方法的不一樣之處在於,拉鍊法把發生衝突的關鍵碼存儲在哈希表主表以外,而開地址法把發生衝突的關鍵碼存儲在表中另外一個槽內。
拉鍊法的一種簡單形式是把哈希表中的每個槽定義爲一個鏈表的表頭,哈希到一個特定槽的全部記錄都放到這個槽的鏈表中。
假設S={and, apple, begin, do, dog, else, for, go, golang},哈希函數仍是關鍵碼K的第一個字母在字母表中的序號。哪麼能夠創建以下的哈希表:
開地址法把全部記錄直接存儲在哈希表中。每一個記錄關鍵碼K有一個由哈希函數計算出來的基位置,即h(k)。若是要插入一個關鍵碼k,而另外一個記錄的關鍵碼已經佔據了k的基位置(發生衝突)則把k存儲在表中的其餘地址內,至於其餘地址怎麼選擇,有多種算法,咱們以順序探測法爲例。
已知一組關鍵碼爲{26,36,41,38,44,15,68,12,06,51,25},哈希表長度L=15,用線性探查法解決衝突構造的哈希表的過程以下:
利用除餘數做爲哈希函數,假設選擇M=13,則散列函數爲:h(k)=k%13,按順序插入各個結點:
h(26)=0, h(36)=10,h(41)=2, h(38)=12, h(44)=5,
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
26 | 25 | 41 | 44 | 36 | 38 |
h(15)=0,發生碰撞,所以須要進行探查,按照順序探測法,顯然3爲開放的空閒地址,所以能夠將其放在3單元。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
26 | 25 | 41 | 15 | 44 | 36 | 38 |
68和12也相似,最後的哈希表以下所示:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
26 | 25 | 41 | 15 | 68 | 44 | 6 | 36 | 38 | 12 | 51 |
本文簡述了哈希表的基本概念和思想,做爲軟件工程師,掌握這些知識足夠咱們從事工程開發了,至於一些偏數學方面的知識,好比散列方法的效率分析,以及相關的一些優化,本文就再也不講述。
參考資料:《數據結構與算法》張銘 編著