雜湊表的英文叫「hash table」,我們平時也叫它「雜湊表」或者「hash 表」,雜湊錶用的是陣列支援按照下標隨機訪問資料的特性,所以雜湊表其實就是陣列的一種擴充套件,由陣列演化而來。可以說,如果沒有陣列,就沒有雜湊表。
假如我們有 89 名選手參加學校運動會。為了方便記錄成績,每個選手胸前都會貼上自己的參賽號碼。這 89 名選手的編號依次是 1 到 89。現在我們希望程式設計實現這樣乙個功能,通過編號快速找到對應的選手資訊。你會怎麼做呢?我們可以把這 89 名選手的資訊放在陣列裡。編號為 1 的選手,我們放到陣列中下標為 1 的位置;編號為 2 的選手,我們放到陣列中下標為 2 的位置。以此類推,編號為 k 的選手放到陣列中下標為 k 的位置。因為參賽編號跟陣列下標一一對應,當我們需要查詢參賽編號為 x 的選手的時候,我們只需要將下標為 x 的陣列元素取出來就可以了,時間複雜度就是 o(1)。這樣按照編號查詢選手資訊,效率是不是很高?
實際上,這個例子已經用到了雜湊的思想。在這個例子裡,參賽編號是自然數,並且與陣列的下標形成一一對映,所以利用陣列支援根據下標隨機訪問的時候,時間複雜度是 o(1) 這一特性,就可以實現快速查詢編號對應的選手資訊。但是這個例子雜湊思想還不夠明顯,那我來改造一下這個例子。
假設校長說,參賽編號不能設定得這麼簡單,要加上年級、班級這些更詳細的資訊,所以我們把編號的規則稍微修改了一下,用 6 位數字來表示。比如 051167,其中,前兩位 05 表示年級,中間兩位 11 表示班級,最後兩位還是原來的編號 1 到 89。這個時候我們該如何儲存選手資訊,才能夠支援通過編號來快速查詢選手資訊呢?思路還是跟前面類似。儘管我們不能直接把編號作為陣列下標,但我們可以擷取參賽編號的後兩位作為陣列下標,來訪問選手資訊資料。當通過參賽編號查詢選手資訊的時候,我們用同樣的方法,取參賽編號的後兩位,作為陣列下標,來讀取陣列中的資料。
這就是典型的雜湊思想。其中,參賽選手的編號我們叫作鍵(key)或者關鍵字。我們用它來標識乙個選手。我們把參賽編號轉化為陣列下標的對映方法就叫作雜湊函式(或「hash 函式」「雜湊函式」),而雜湊函式計算得到的值就叫作雜湊值(或「hash 值」「雜湊值」)。
雜湊函式顧名思義首先它是乙個函式,我們可以簡單定義它為hash(key),key為元素的鍵值,hash(key)生成的值叫做雜湊值。
乙個雜湊函式應該滿足哪些條件:
上述的第三情況屬於理論上,因為真實情況下幾乎不存在每個不同的key對應不同的雜湊值,雜湊衝突幾乎是不可避免的。因此我們需要找到一些方法盡量來減少雜湊衝突,後面會講述。
雜湊錶用的就是陣列支援按照下標隨機訪問的時候,時間複雜度是 o(1) 的特性。我們通過雜湊函式把元素的鍵值對映為下標,然後將資料儲存在陣列中對應下標的位置。當我們按照鍵值查詢元素時,我們用同樣的雜湊函式,將鍵值轉化陣列下標,從對應的陣列下標的位置取資料。
/** * @description 在字典中我們是用鍵值對來儲存資料 */const assert = require("assert");// 雜湊函式const loselosehashcode = (key = '') => return hashcode % 37}class hashtable put(key, value) remove(key) return false } get(key) getitems() }// test caseconst hashtable = new hashtable()hashtable.put("jobs", "[email protected]");hashtable.put("bob", "[email protected]");console.log(hashtable.getitems());assert.strictequal(hashtable.remove('bob'), true);console.log(hashtable.getitems());assert.strictequal(hashtable.get('jobs'), '[email protected]');
在真實的情況下,要想找到乙個不同的 key 對應的雜湊值都不一樣的雜湊函式,幾乎是不可能的。即便像業界著名的md5、sha、crc等雜湊演算法,也無法完全避免這種雜湊衝突。而且,因為陣列的儲存空間有限,也會加大雜湊衝突的概率。所以我們幾乎無法找到乙個完美的無衝突的雜湊函式,即便能找到,付出的時間成本、計算成本也是很大的,所以針對雜湊衝突問題,我們需要通過其他途徑來解決。
在雜湊表中,每個「桶(bucket)」或者「槽(slot)」會對應一條鍊錶,所有雜湊值相同的元素我們都放到相同槽位對應的鍊錶中。
當插入的時候,我們只需要通過雜湊函式計算出對應的雜湊槽位,將其插入到對應鍊錶中即可,所以插入的時間複雜度是 o(1)。當查詢、刪除乙個元素時,我們同樣通過雜湊函式計算出對應的槽,然後遍歷鍊錶查詢或者刪除。那查詢或刪除操作的時間複雜度是多少呢?實際上,這兩個操作的時間複雜度跟鍊錶的長度 k 成正比,也就是 o(k)。對於雜湊比較均勻的雜湊函式來說,理論上講,k=n/m,其中 n 表示雜湊中資料的個數,m 表示雜湊表中「槽」的個數。
資料結構 雜湊表
1.雜湊表的定義 元素的儲存位置和它的關鍵碼之間建立乙個確定的對應關係h,使得每個關鍵碼key和唯一的儲存位置h key 相對應。在查詢時,根據這個確定的對應關係找到給定值k的對映h k 若查詢集合中存在這個記錄,則必定在h k 的位置上,這種查詢技術稱為雜湊技術。採用雜湊技術將記錄儲存在一塊連續的...
資料結構 雜湊表
雜湊表的定義 雜湊表 hash table,也叫雜湊表 是根據關鍵碼值 key value 而直接進行訪問的資料結構。也就是說,它通過把 關鍵碼值對映到表中乙個位置來訪問記錄,以加快查詢的 速度。這個對映函式叫做雜湊函式,存放 記錄的陣列叫做雜湊表。雜湊函式的析構方法 餘數法 取關鍵字被某個不大於雜...
資料結構 雜湊表
3 雜湊函式 數字分析法 根據關鍵碼在各個位上的分布情況,選取分布比較均勻的若干位組成雜湊位址。適用情況 能預先估計出全部關鍵碼的每一位上各種數字出現的頻度,不同的關鍵碼集合需要重新分析。4 雜湊函式 平方取中法 對關鍵碼平方後,按照雜湊表大小,取中間的若干位作為雜湊位址 平方後擷取 適用情況 實現...