雜湊表 又叫 雜湊表 (hash table)。通過訪問key而直接訪問儲存的value值。它的key - value之間存在乙個對映函式,我們可以通過key值和「看不到」的對映函式(雜湊函式)訪問對應的value值。這加快了查詢的速度!存放記錄的陣列稱做雜湊表。雜湊方法不同於順序查詢、二分查詢、二叉排序樹及b-樹上的查詢。它不以關鍵字的比較為基本操作,採用直接定址技術 (就是說,它是直接通過key對映[對映函式,實現的方式有多種] 到記憶體位址上去的)。在理想情況下,無須任何比較就可以找到待查關鍵字,查詢的期望時間為o(1)(面試的時候犯了這個錯誤)。
舉個形象的例子來說:為了查詢**簿中某人的號碼,可以建立乙個按照人名首字母順序排列的表(即建立人名x到首字母f(x)的乙個函式關係),在首字母為w的表中查詢「王」姓的**號碼,顯然比直接查詢就要快得多。這裡使用人名作為關鍵字,「取首字母」是這個例子中雜湊函式的函式法則f(),存放首字母的表對應雜湊表。關鍵字和函式法則理論上可以任意確定。[維基百科]
雜湊表設所有可能出現的關鍵字集合記為u(簡稱全集)。實際發生(即實際儲存)的關鍵字集合記為k(|k|比|u|小得多)。
雜湊方法是使用函式h將u對映到表t[0…m-1]的下標上(m=o(|u|))。這樣以u中關鍵字為自變數,以h為函式的運算結果就是相應結點的儲存位址。從而達到在o(1)時間內就可完成查詢。
其中:① h:u→ ,通常稱h為雜湊函式(hash function)。雜湊函式h的作用是壓縮待處理的下標範圍,使待處理的|u|個值減少到m個值,從而降低空間開銷。
② t為雜湊表(hash table)。
③ h(ki)(ki∈u)是關鍵字為ki結點儲存位址(亦稱雜湊值或雜湊位址)。
④ 將結點按其關鍵字的雜湊位址儲存到雜湊表中的過程稱為雜湊(hashing)
我們基本知道了value和key之間存在乙個對映關係h,簡單的表示為 value = h(key)。 我們會有疑問,函式以允許多對一出現的,也就是說,當多個key對應乙個value時怎麼辦?
這就是雜湊表中的衝突。
雜湊表的衝突現象
(1)衝突
兩個不同的關鍵字,由於雜湊函式值相同,因而被對映到同一表位置上。該現象稱為衝突(collision)或碰撞。發生衝突的兩個關鍵字稱為該雜湊函式的同義詞(synonym)。
【例】上圖中的k2≠k5,但h(k2)=h(k5),故k2和k5所在的結點的儲存位址相同。
(2)安全避免衝突的條件
最理想的解決衝突的方法是安全避免衝突。要做到這一點必須滿足兩個條件:
①其一是|u|≤m
②其二是選擇合適的雜湊函式。
這只適用於|u|較小,且關鍵字均事先已知的情況,此時經過精心設計雜湊函式h有可能完全避免衝突。
(3)衝突不可能完全避免
通常情況下,h是乙個壓縮映像。雖然|k|≤m,但|u|>m,故無論怎樣設計h,也不可能完全避免衝突。因此,只能在設計h時盡可能使衝突最少。同時還需要確定解決衝突的方法,使發生衝突的同義詞能夠儲存到表中。
通常有兩類方法處理碰撞:開放定址(open addressing)法和鏈結(chaining)法。前者是將所有結點均存放在雜湊表t[0…m-1]中;後者通常是把雜湊到同一槽中的所有元素放在乙個鍊錶中,而將此鍊錶的頭指標放在雜湊表t[0…m-1]中。
(1)開放定址法
所有的元素都在雜湊表中,每乙個表項或包含動態集合的乙個元素,或包含nil。這種方法中雜湊表可能被填滿,以致於不能插入任何新的元素。在開放定址法中,當要插入乙個元素時,可以連續地檢查或探測雜湊表的各項,直到有乙個空槽來放置待插入的關鍵字為止。有三種技術用於開放定址法:線性探測、二次探測以及雙重探測。
<1>線性探測
給定乙個普通的雜湊函式h』:u —>,線性探測方法採用的雜湊函式為:h(k,i) = (h』(k)+i)mod m,i=0,1,…,m-1
探測時從i=0開始,首先探查t[h'(k)],然後依次探測t[h'(k)+1],…,直到t[h'(k)+m-1],此後又迴圈到t[0],t[1],…,直到探測到t[h'(k)-1]為止。探測過程終止於三種情況:
(1)若當前探測的單元為空,則表示查詢失敗(若是插入則將key寫入其中);
(2)若當前探測的單元中含有key,則查詢成功,但對於插入意味著失敗;
(3)若探測到t[h』(k)-1]時仍未發現空單元也未找到key,則無論是查詢還是插入均意味著失敗(此時表滿)。
線性探測方法較容易實現,但是存在一次群集問題,即連續被占用的槽的序列變的越來越長。採用例子進行說明線性探測過程,已知一組關鍵字為(26,36,41,38,44,15,68,12,6,51),用除餘法構造雜湊函式,初始情況如下圖所示:
雜湊過程如下圖所示:
<2>二次探測
二次探測法的探查序列是:h(k,i) =(h』(k)+i*i)%m ,0≤i≤m-1 。初次的探測位置為t[h』(k)],後序的探測位置在次基礎上加乙個偏移量,該偏移量以二次的方式依賴於i。該方法的缺陷是不易探查到整個雜湊空間。
<3>雙重雜湊
該方法是開放定址的最好方法之一,因為其產生的排列具有隨機選擇的排列的許多特性。採用的雜湊函式為:h(k,i)=(h1(k)+ih2(k)) mod m。其中h1和h2為輔助雜湊函式。初始探測位置為t[h1(k)],後續的探測位置在此基礎上加上偏移量h2(k)模m。
(2)鏈結法
將所有關鍵字為同義詞的結點鏈結在同乙個鍊錶中。若選定的雜湊表長度為m,則可將雜湊表定義為乙個由m個頭指標組成的指標陣列t[0…m-1]。凡是雜湊位址為i的結點,均插入到以t[i]為頭指標的單鏈表中。t中各分量的初值均應為空指標。在拉鍊法中,裝填因子α可以大於1,但一般均取α≤1。
最終結果如下圖所示:
構造雜湊函式
(直接複製的維基百科,詳細可參見[1]) 雜湊函式能使對乙個資料序列的訪問過程更加迅速有效,通過雜湊函式,資料元素將被更快定位。
直接定址法:取關鍵字或關鍵字的某個線性函式值為雜湊位址。即hash(k)=k或hash(k)=a\cdot k + b,其中a,b為常數(這種雜湊函式叫做自身函式)
數字分析法:假設關鍵字是以r為基的數,並且雜湊表中可能出現的關鍵字都是事先知道的,則可取關鍵字的若干數字組成雜湊位址。
平方取中法:取關鍵字平方後的中間幾位為雜湊位址。通常在選定雜湊函式時不一定能知道關鍵字的全部情況,取其中的哪幾位也不一定合適,而乙個數平方後的中間幾位數和數的每一位都相關,由此使隨機分布的關鍵字得到的雜湊位址也是隨機的。取的位數由表長決定。
摺疊法:將關鍵字分割成位數相同的幾部分(最後一部分的位數可以不同),然後取這幾部分的疊加和(捨去進製)作為雜湊位址。
隨機數法
除留餘數法:取關鍵字被某個不大於雜湊表表長m的數p除后所得的餘數為雜湊位址。即hash(k)=k ,\bmod ,p, p\le m。不僅可以對關鍵字直接取模,也可在摺疊法、平方取中法等運算之後取模。對p的選擇很重要,一般取素數或m,若p選擇不好,容易產生碰撞。
查詢效率
雜湊表的查詢過程基本上和造表過程相同。一些關鍵碼可通過雜湊函式轉換的位址直接找到,另一些關鍵碼在雜湊函式得到的位址上產生了衝突,需要按處理衝突的方法進行查詢。在介紹的三種處理衝突的方法中,產生衝突後的查詢仍然是給定值與關鍵碼進行比較的過程。所以,對雜湊表查詢效率的量度,依然用平均查詢長度來衡量。
查詢過程中,關鍵碼的比較次數,取決於產生衝突的多少,產生的衝突少,查詢效率就高,產生的衝突多,查詢效率就低。因此,影響產生衝突多少的因素,也就是影響查詢效率的因素。影響產生衝突多少有以下三個因素:
雜湊函式是否均勻;
處理衝突的方法;
雜湊表的載荷因子(load factor)。
本文參考:
1.2.
雜湊表(雜湊表)原理詳解
雜湊表 hash table,也叫雜湊表 是 根據關鍵碼值 key value 而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中乙個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做 雜湊函式 存放記錄的陣列叫做 雜湊表。或者 把任意長度的輸入 又叫做預對映,pre image 通過雜...
雜湊表(雜湊表)原理詳解
t什麼是雜湊表?雜湊表 hash table,也叫雜湊表 是根據關鍵碼值 key value 而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中乙個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表。記錄的儲存位置 f 關鍵字 這裡的對應關係f稱為雜湊函...
詳解雜湊表(雜湊表)原理
場景 在我們編寫基本的c語言 的時候,比如我們需要輸入乙個變數,然後對變數進行操作,最後返回乙個結果,那麼在我們對變數進行操作的時候,我們的編譯器就會對你的變數進行檢查,他會看你的變數是否定義 定義格式是否正確等。這裡就會存在查詢問題,如果我們採用二叉查詢樹等查詢樹來進行查詢的話會發現由於需要使樹保...