資料結構 全面學習雜湊

2021-07-04 16:10:33 字數 3199 閱讀 4398

相信學計算機的童鞋對於「雜湊」這個詞會很熟悉,但是能明明白白的說清楚,並且用程式來描述的人還是比較少的。這裡,我們就全面學習這個重要的資料結構,以及它的思想和應用。

首先,我們來學習一下幾個基本概念。

雜湊(hash)

雜湊表(hash table)

一種資料表結構。hash表,有時候也被稱為雜湊表。個人認為,hash表是介於鍊錶和二叉樹之間的一種中間結構。鍊錶使用十分方便,但是資料查詢十分麻煩;二叉樹中的資料嚴格有序,但是這是以多乙個指標作為代價的結果。hash表既滿足了資料的查詢方便,同時不占用太多的內容空間,使用也十分方便。

打個比方來說,所有的資料就好像許許多多的書本。如果這些書本是一本一本堆起來的,就好像鍊錶或者線性表一樣,整個資料會顯得非常的無序和凌亂,在你找到自己需要的書之前,你要經歷許多的查詢過程;而如果你對所有的書本進行編號,並且把這些書本按次序進行排列的話,那麼如果你要尋找的書本編號是n,那麼經過二分查詢,你很快就會找到自己需要的書本;但是如果你每乙個種類的書本都不是很多,那麼你就可以對這些書本進行歸類,哪些是文學類,哪些是藝術類,哪些是工科的,哪些是理科的,你只要對這些書本進行簡單的歸類,那麼尋找一本書也會變得非常簡單,比如說如果你要找的書是計算機方面的書,那麼你就會到工科一類當中去尋找,這樣查詢起來也會顯得麻煩。

映像

由雜湊函式得到的雜湊表是乙個映像。

衝突

如果兩個關鍵字的雜湊函式值相等,這種現象稱為衝突。

雜湊演算法

並不是乙個特定的演算法而是一類演算法的統稱。 雜湊演算法也叫雜湊演算法,一般來說滿足這樣的關係:f(data)=key,輸入任意長度的data資料,經過雜湊演算法處理後輸出乙個定長的資料key。同時這個過程是不可逆的,無法由key逆推出data。

處理衝突的幾個方法(後面的程式會詳解)

開放位址法:用開放位址處理衝突就是當衝突發生時,形成乙個位址序列,沿著這個序列逐個深測,直到找到乙個「空」的開放位址,將發生衝突的關鍵字值存放到該位址中去。 例如:hash(i)=(hash(key)+d(i)) mod m (i=1,2,3,......,k(k

鏈位址法:把所有關鍵字為同義詞的記錄儲存在乙個線性鍊錶中,這個鍊錶成為同義詞鍊錶,即把具有相同雜湊位址的關鍵字值存放在同義鍊錶中。

二次雜湊表:費時間的一種方法 如果是乙個data資料集,經過雜湊演算法處理後得到key的資料集,然後將keys與原始資料進行一一對映就得到了乙個雜湊表。一般來說雜湊表m符合m[key]=data這種形式。 雜湊表的好處是當原始資料較大時,我們可以用雜湊演算法處理得到定長的雜湊值key,那麼這個key相對原始資料要小得多。我們就可以用這個較小的資料集來做索引,達到快速查詢的目的。

稍微想一下就可以發現,既然輸入資料不定長,而輸出的雜湊值卻是固定長度的,這意味著雜湊值是乙個有限集合,而輸入資料則可以是無窮多個。那麼建立一對一關係明顯是不現實的。所以"碰撞"(不同的輸入資料對應了相同的雜湊值)是必然會發生的,所以乙個成熟的雜湊演算法會有較好的抗衝突性。同時在實現雜湊表的結構時也要考慮到雜湊衝突的問題。

密碼上常用的md5,sha都是雜湊演算法,因為key的長度(相對大家的密碼來說)較大所以碰撞空間較大,有比較好的抗碰撞性,所以常常用作密碼校驗。

下面,我們通過乙個例子,來自己實現乙個完整的雜湊表

問題描述:針對某個集體(比如你所在的班級)中的「人名」設計乙個雜湊表,使得平均查詢長度不超過r,完成相應的建表和查表程式。

思路:假設人名為中國人姓名的漢語拼音形式。待填入雜湊表的人名共有30個,取平均查詢長度的上限為2。雜湊函式用除留餘數法構造,用偽隨機探測再雜湊法處理衝突。

**如下 :

#include #include #include #include #ifndef _hashtest_h_

#define _hashtest_h_

#define name_no 30

#define hash_length 50

#define m 50;

using namespace std;

typedef struct

name;

typedef struct //雜湊表

hash;

#endif

hash hashlist[hash_length],namelist[hash_length];

void initnamelist()

while(ch1!='n');

return 0;

}

我們執行這段程式,會出現如下結果:

根據輸出我們可以看到四個值:

關鍵字就是拼音的ascll碼之和。然後通過雜湊函式形成了乙個值,我們叫做value這段程式是用50取餘數之後得到的,所以key值在0~50之間。這個value值決定了資料存放的位置,所以能看到value值跟位址很多是一樣的。這裡是如何解決「衝突」的呢。如果有兩個元素的經過雜湊函式之後的結果是一樣的呢?這裡定義了乙個si的值,意思為搜尋次數,如果沒有衝突意思是一次性找到了位置。

我們來看這一段函式 

else //衝突,d的初始值為adr,adr意思是address,也是value值賦予的

while(hashlist[d].k!=0); //找到空位

hashlist[d].k=namelist[i].k; //放入元素

hashlist[d].py=namelist[i].py;

hashlist[d].si=sum+1;

}

其中 

d=(d+namelist[i].k%10+1)%m
叫做偽隨機探測再雜湊法處理衝突,就是將雜湊值(value),d,重新雜湊一次重新獲得一次d的值找到乙個空的位置,把元素塞進去。

再看一看key是如何得到的,也就是姓名的ascll碼之和是如何得到的。  

for(i=0;i這裡注意一下,f是字元型別,r是int型,有乙個型別轉換在這裡。



資料結構 雜湊

裝填因子 key的個數與表長的比值。雜湊表查詢成功的平均查詢長度,查詢失敗的平均查詢長度都是期望,期望怎麼求,平均查詢長度就怎麼求。雜湊表這裡有兩種實現方式 線性開型定址雜湊,鍊錶雜湊。1.線性開型定址雜湊 陣列實現,資料個數不大於表長,放乙個元素時,若發生衝突,則順次線性掃瞄直到找到乙個空位。2....

資料結構 雜湊

關鍵 不比較關鍵碼,直接搜尋得到需要的數。特點 與搜尋樹不一樣,雜湊結構元素的儲存位置與關鍵碼直接對應,可以不用進行比較遍歷。如圖,建立乙個陣列,把a 4 中的資料按特定的規則儲存到相應的位置,比如a i n,到時候搜尋資料的時候可以按照同樣的規律直接找到這個位置,如果這個位置有數,則存在。比如按照...

資料結構 雜湊

將元素的儲存位置和該元素的關鍵碼通過某種函式建立一一對應的關係,構造出來的儲存結構稱之為雜湊表,轉換時借助的函式稱之為雜湊函式,在理想情況下,根據關鍵碼搜尋元素時可以不經過任何比較,一次性從表中查詢到所要搜尋的元素 但是在通過雜湊函式進行元素儲存位置確立的時候會出現,不同元素的關鍵碼通過雜湊函式計算...