談談雜湊表

2021-08-09 09:49:46 字數 3718 閱讀 5460

一、什麼是雜湊表?

雜湊表簡單來說可以看作是是對陣列的公升級,(也有不少人認為雜湊表的本質就是陣列),那麼雜湊表和陣列的具體聯絡和區別在**呢?

我們在利用陣列儲存資料的時候,記錄在陣列中的位置是隨機的,位置和記錄的關鍵字之間不存在確定的關係。

聯絡:雜湊表是由陣列實現的。

區別:陣列中儲存的元素的和陣列下標沒有確定的關係,而雜湊表中儲存的元素和陣列的下標有乙個確定的關係,我們將這個確定的關係稱之為雜湊函式(hash).

1、最簡單的例子:

我們可以舉乙個最簡單的例子。假設要建立一張全班40個學生的情況統計表,每乙個學生為乙個記錄,記錄的各項資料為:

很明顯我們可以利用乙個一維陣列s[40]來存放它,當我們要查詢某乙個學生的資訊的時候,我們可以以學生的學號來作為關鍵字查詢,陣列的位置即陣列的下標和學號沒有確定的關係如圖二:

圖二

那麼我們根據學號這個關鍵字來查詢記錄的時候,需要把關鍵字和陣列中的每一記錄進行比較。遍歷整個陣列。

當我們用乙個確定的關係即雜湊函式(hash)來確定關鍵字和記錄的儲存位置時,換句話說確定學號和陣列下標的對應關係。那麼這個陣列就可稱之為雜湊表。

如圖三

圖三這樣我們查詢學號為2015550403的學生資訊,就可以直接找到它的儲存位置,它對應的下標為3。這樣我們把關鍵字key和儲存位置hash(key)之間的對應關係 稱之為雜湊函式hash,按這個思想建立的表為雜湊表。

在上述例子中,我們採用的構造雜湊函式的方法為直接定址法。取關鍵字或關鍵字的某乙個線性函式作為雜湊位址。

hash(key)=key或hash(key)=a*key+b.

上述例子中hash(key)=key-201555040

2、對最簡單例子的改變

當然在實際生活中我們查詢乙個班級的學生情況的時候,往往更傾向於用名字作為關鍵字來查詢記錄,比如老師更傾向於詢問「劉耀的**是多少啊?」而不是「2015550403 的**是多少啊?」。假設學生姓名以漢語的小寫拼音的字元表示,則不能再簡單地取hash(key)=a*key+b,而是首先要將它們轉為數字,並對他們進行簡單的處理。簡單的舉乙個例子雜湊函式:取關鍵字的第乙個字母的ascii碼,再對10取餘所得的餘數便是記錄在陣列中的下標值。

如關鍵字陳葳蕤(陳葳蕤)第一字母為c ascii碼為99,99對10取余為9,則陳葳蕤的記錄在雜湊表的中的下標為9.

圖四:我們可以從這個例子中得知

(1)雜湊函式的設定很靈活,只要關鍵字通過雜湊函式能夠唯一確定乙個雜湊位址,而且改位址在陣列的大小範圍內就可以了。當然陣列的長度也是我們自己設定的。

(2)對於不同的關鍵字,可能得到同乙個雜湊位址,這種關鍵字我們稱之為同義詞,如上圖中宋澤和蔡布思的雜湊位址均為9,那麼宋澤何蔡布思為同義詞,而s[9]只能儲存乙個記錄,這種情況叫做衝突。一般情況下,衝突只能盡可能地減少並不能完全避免。那麼怎麼處理衝突問題呢?

我們接下來慢慢講解,其中一種最常見的方法是鏈位址法:建乙個元素為鍊錶的陣列,陣列大小為雜湊函式產生的雜湊位址的區間,每個陣列元素初始都為空,所有關鍵字為同義詞的記錄儲存在同乙個煉表裡,但凡是雜湊位址為i的記錄都插在s[i]這個元素後面。如圖五所示給出四個學生裡面一部分學生的雜湊表儲存情況。

通過以上兩個簡單的例子我想大家對雜湊表應該有個大體的印象了吧,那麼我再來描述一下雜湊表:通過乙個雜湊函式hash(key)和處理衝突方法將乙個關鍵字對映到乙個連續的位址集上,並以關鍵字在位址集上的像作為記錄在表中的儲存位置。這種表或者結構稱為雜湊表。通俗點講就是利用關鍵字通過乙個函式hash(key)確定記錄在陣列中的下標。

二、雜湊函式的構造方法

(1)直接定址法:這個方法我們在上述例子中有用到過,取關鍵字的或關鍵的某乙個線性函式值為雜湊位址。即:hash(key)=key或者hash(key)=a*key+b。這種構造方法下由於位址集合和關鍵字集合大小一樣,所以並不會有衝突的發生。但是這種方法並不常用。

(2)除留餘數法:這個方法我們在上述例子中也有用到過,取關鍵字被某乙個不大於雜湊表長m的數p除后所餘得的數為雜湊位址。即hash(key)=key mod p,p<=m(m為雜湊表長)。這種方法比較簡單也很常用。

可以看到:在雜湊函式構造的時候都是使用的數字,但如果我們的關鍵字不為數字的時候,我們要先將關鍵字轉化為數字,再用雜湊函式得到雜湊位址。如上述例子中我們利用學生姓名作為關鍵字,我們首先要得到學生姓名小寫拼音的ascii碼,再用ascii碼作為雜湊函式的自變數,從而得到雜湊位址。

三、雜湊表處理衝突的方法

之前講過雜湊表的衝突是不可避免的只能減少的,那麼如何處理衝突也成了乙個不可避免的問題。

什麼是處理衝突呢?:由關鍵字得到的雜湊位址上已經有記錄存在了,那麼「處理衝突」就是要為該關鍵字的記錄找到乙個「沒有記錄存在」的雜湊位址。在處理衝突的過程中可能得到乙個位址序列hi(i=1,2,3,4,5,……)。我們在處理雜湊衝突的時候可能得到的另乙個雜湊位址h1也是有記錄的,我們要求下乙個位址h2,如果h2依然衝突,則找h3,依次類推,直至hi上沒有記錄為止。

其中:hash(key)為雜湊函式,di為增量序列,m為雜湊表長。

1、di=1,2,3,4,5……,m-1時稱線性探測再雜湊;

2、di=12,-12,22,-22……….,+k2,-k2(k<=m/2)稱之為二次探測再雜湊。

3、di=偽隨機數序列,稱之為隨機探測在雜湊。

(2)再雜湊法:hi=rhashi(key) i=0,1,2,3,4….,k. rhashi均是不同的雜湊函式,就是說在同義詞產生位址衝突的時候用另乙個雜湊函式去求得另乙個雜湊位址,一直到不再有衝突

乙個基本表elemtype base_tbl[m];每個單元只能存放乙個元素;

乙個溢位表elemtype over_tbl[k];只要關鍵碼對應的雜湊位址在基本表上產生衝突,則所有這樣的元素一律存入該表中。查詢時,對給定值kx 通過雜湊函式計算出雜湊位址i,先與基本表的base_tbl[i]單元比較,若相等,查詢成功;否則,再到溢位表中進行查詢。

四、雜湊表的查詢

1、理想情況下我們根據關鍵字key,通過造表時候的雜湊函式求得雜湊位址,該錶此位置上的記錄的關鍵字與我們給定的關鍵字key相等,則查詢成功。

2、但是如果有衝突,即該表此位置上的記錄不是我們要查詢的記錄,則根據造表時候設定的衝突處理方法尋找「下乙個位址」,一直到雜湊表的某乙個位置為「空」或者表中記錄的關鍵字為我們給定的關鍵字key。

五、總結

理論上來講雜湊表訪問某乙個記錄的時間開銷是o(1),直接通過雜湊函式和關鍵字找到記錄的儲存位址,但是由於衝突的產生,使得雜湊表的查詢過程仍然需要關鍵字去和乙個雜湊表中的元素來進行比較。也就是說雜湊表盡可能地減少我們要比較的次數,如果能夠經過計算查詢到我們要訪問的記錄那是最理想的情況。但是由於衝突導致我們還需要進行「比較」。

打個比方:

這就像我們去利用字典查詢漢字,我們雖然能夠利用漢字的首字母或者漢子的筆畫去確定該漢字在字典中的頁碼,但是該頁碼中還存在其他的漢字,我們需要將查詢的漢字和該頁碼中的漢字進行比較,直到找到我們要查詢的漢字。在利用字典查詢漢字的過程中,我們雖然仍然要去比較漢字,但相比與在所有頁碼中去乙個個比較查詢,這種先確定頁碼再去比較的方案已經能極大地提高我們查詢的效率了。我想這就是雜湊表存在的意義吧。

雜湊表 雜湊表

一 定義 雜湊表 hash table,也叫雜湊表 是根據關鍵碼值 key value 而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中乙個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表。雜湊表的做法其實很簡單,就是把key通過乙個固定的演算法函式...

雜湊表(雜湊表)

雜湊表是最基礎的資料結構之一,利用鍵值對儲存並檢索資料的一種非線性結構。在其它各種結構線性表 樹等資料結構中,記錄在結構中的位置是隨機的,和記錄關鍵字之間不存在確定的關係,因此,在結構中查詢記錄時需進行一系列和關鍵字的 比較 的基礎上。在順序查詢時,比較的結果為 與 兩種可能 在折半查詢 二叉排序樹...

雜湊表(雜湊表)

原文 雜湊表是種資料結構,它可以提供快速的插入操作和查詢操作。第一次接觸雜湊表時,它的優點多得讓人難以置信。不論雜湊表中有多少資料,插入和刪除 有時包括側除 只需要接近常量的時間即0 1 的時間級。實際上,這只需要幾條機器指令。對雜湊表的使用者一一人來說,這是一瞬間的事。雜湊表運算得非常快,在電腦程...