哈希函數的構造方法

哈希函數的構造方法

本文闡述了哈希函數的構造方法有很多,但應注意兩個原則:第一,函數值應在1至記錄總數之間;第二,儘可能避免衝突。

設要存放的數據元素有n個,存放數據元素的內存單元有m個,設計哈希函數的目標就是要使通過哈希函數得到的n個數據元素的哈希地址儘可能均勻地分佈在m個連續內存單元上,同時使計算過程儘可能簡單以達到儘可能高的時間效率。

引 言
構造哈希函數的方法很多。如何構造一個“好”的哈希函數是很強的技術性和實踐性問題,這裏的“好”指的是哈希函數構造比較簡單,並且用此哈希函數產生的映射所發生的衝突可能性最小,換句話說一個好的哈希函數能將給定數據集合均勻地映射到給定的地址區間中。

Hash的原意是“弄亂,切碎”,這裏的含義是“雜湊”。基本做法是,根據集合元素值的分佈情況,設計一個哈希函數h(ki),存儲之素ki時,計算ki的哈希函數值,元素ki存儲在a(h)中。

如果“幸運”,所設計的哈希函數很均勻,即任何ki≠kj,都有h(ki)≠h(kj),那麼在查找ki時(再計算ki的哈希函數函數值h),就能在a[h]中找到元素ki。

1.直接定址法
直接定址法是以數據元素關鍵字k本身或它的線性函數作爲它的哈希地址,即:H(k)=k 或 H(k)=a×k+b ; (其中a,b爲常數)

例1,有一個人口統計表,記錄了從1歲到100歲的人口數目,其中年齡作爲關鍵字,哈希函數取關鍵字本身,如圖(1):

地址

A1

A2

……

A99

A100

年齡

1

2

……

99

100

人數

980

800

……

495

107

可以看到,當需要查找某一年齡的人數時,直接查找相應的項即可。如查找99歲的老人數,則直接讀出第99項即可。這種哈希函數簡單,並且對於不同的關鍵字不會產生衝突,但可以看出這是一種較爲特殊的哈希函數,實際生活中,關鍵字的元素很少是連續的。用該方法產生的哈希表會造成空間大量的浪費,因此這種方法適應性並不強。[2]↑

2.數字分析法
2.1數字分析法是取數據元素關鍵字中某些取值較均勻的數字位作爲哈希地址的方法。即當關鍵字的位數很多時,可以通過對關鍵字的各位進行分析,丟掉分佈不均勻的位,作爲哈希值。它只適合於所有關鍵字值已知的情況。通過分析分佈情況把關鍵字取值區間轉化爲一個較小的關鍵字取值區間。

例2,要構造一個數據元素個數n=80,哈希長度m=100的哈希表。不失一般性,我們這裏只給出其中8個關鍵字進行分析,8個關鍵字如下所示:

K1=61317602 K2=61326875 K3=62739628 K4=61343634

K5=62706815 K6=62774638 K7=61381262 K8=61394220

分析上述8個關鍵字可知,關鍵字從左到右的第1、2、3、6位取值比較集中,不宜作爲哈希地址,剩餘的第4、5、7、8位取值較均勻,可選取其中的兩位作爲哈希地址。設選取最後兩位作爲哈希地址,則這8個關鍵字的哈希地址分別爲:2,75,28,34,15,38,62,20。[1]↑

  1. 2設有n個d 位數,每一位可能有r種不同的符號,這r種不同的符號在各位上出現的頻率不一定相同,可能在某位上分佈均勻些,每種符號出現的機會均等;在某位上分佈不均勻,只有某幾種符號經常出現。可根據哈希表的大小,選取其中各種符號分佈均勻的若干位作爲哈希地址。計算各位數字中符號分佈均勻度rk的公式爲:rk=其中,aki表示第i個符號k位上出現的的期望值。計算出rk值越小,

i=1

表明在該位(第k位)各種符號分佈越不均勻。

例3,有一組關鍵字,對其各位編碼如下:

9 2 1 4 8

9 1 2 6 9

9 0 5 2 7

9 1 6 3 0

9 1 8 0 5

9 1 5 5 8

9 2 0 4 7

9 0 0 0 1

① ② ③ ④ ⑤

①位僅“9”出現8次r1=(8-8/10)2*1+(0-8/10)2*9=57.60

②位“0,2”各出現2次,“1”出現4次r2=(2-8/10)2*2+(4-8/10)2*1+(0-8/10)2*7=17.60

③位“0,5”各出現2次,“1,2,6,8”各出現1次r3=(2-8/10)2*2+(1-8/10)2*4+(0-8/10)2*4=5.60

④位“0,4”各出現2次,“2,3,5,6”各出現1次

⑤位“7,8”各出現2次,“0,1,5,9”各出現1次

r3 =r4 =r5 =5.60

若哈希表地址範圍有3位數字,取各關鍵字的③④⑤位作爲記錄的哈希地址。也可以把第①②和第⑤位想加,捨去進位,變成一位數,再與第③④位合起來哈希地址等。顯然數字分析法僅適用於事先知道表中所有關鍵字每一位數值的分佈情況,它完全依賴於關鍵字集合。如果換一個關鍵字集合,選擇哪幾位重新決定。

3.摺疊法
所謂摺疊法是將關鍵字分割成位數相同的幾部分(最後一部分的位數可以不同),然後取這幾部分的疊加和(捨去進位),這方法稱爲摺疊法。這種方法適用於關鍵字位數較多,而且關鍵字中每一位上數字分佈大致均勻的情況。

摺疊法中數位摺疊又分爲移位疊加和邊界疊加兩種方法,移位疊加是將分割後是每一部分的最低位對齊,然後相加;邊界疊加是從一端向另一端沿分割界來回摺疊,然後對齊相加。

例4,當哈希表長爲1000時,關鍵字key=110108331119891,允許的地址空間爲三位十進制數,則這兩種疊加情況如圖(2):

   移位疊加                                 邊界疊加

   8 9 1                                     8 9 1

   1 1 9                                     9 1 1

   3 3 1                                     3 3 1

   1 0 8                                     8 0 1

+  1 1 0                                   + 1 1 0              

(1) 5 5 9 (3)0 4 4

             圖(2)由摺疊法求哈希地址

 用移位疊加得到的哈希地址是559,而用邊界疊加所得到的哈希地址是44。如果關鍵字不是數值而是字符串,則可先轉化爲數。轉化的辦法可以用ASCⅡ字符或字符的次序值。[3]↑

4.平方取中法
這是一種常用的哈希函數構造方法。這個方法是先取關鍵字的平方,然後根據可使用空間的大小,選取平方數是中間幾位爲哈希地址。

哈希函數 H(key)=“key2的中間幾位”因爲這種方法的原理是通過取平方擴大差別,平方值的中間幾位和這個數的每一位都相關,則對不同的關鍵字得到的哈希函數值不易產生衝突,由此產生的哈希地址也較爲均勻。

例5,若設哈希表長爲1000則可取關鍵字平方值的中間三位,如圖(3)所示:

關鍵字

關鍵字的平方

哈希函數值

1234

1522756

227

2143

4592449

924

4132

17073424

734

3214

10329796

297

圖(3)平方取中哈希函數示例 [4] ↑

有人曾用“輪盤賭”的統計分析方法對它們進行了模擬分析,結論是平方取中法最接近“隨機化”。

例6,設有一組關鍵字值爲ABC,BCD,CDE,DEF其相應的機內碼分別爲010203,020304,030405,040506。假設可利用地址空間大小爲103,平方後取平方數的中間三位作爲相當記錄的存儲地址。如圖(4)所示:

關鍵字

機內碼

機內碼的平方

哈希地址

ABC

010203

0104101209

101

BCD

020304

0412252416

252

CDE

030405

0924464025

464

DEF

040506

1640736036

736

圖(4)平方取中法關鍵字及其存儲地址[6]↑

下面給出平方取中法的哈希函數

 //平方取中法哈希函數,結設關鍵字值32位的整數

 //哈希函數將返回key * key的中間10位

   Int  Hash (int key)

     {

 //計算key的平方

  Key * = key ;

 //去掉低11位

 Key>>=11;

 // 返回低10位(即key * key的中間10位)

   Return key %1024;

      }

5.減去法
減去法是數據的鍵值減去一個特定的數值以求得數據存儲的位置。

例7,公司有一百個員工,而員工的編號介於1001到1100,減去法就是員工編號減去1000後即爲數據的位置。編號1001員工的數據在數據中的第一筆。編號1002員工的數據在數據中的第二筆…依次類推。從而獲得有關員工的所有信息,因爲編號1000以前並沒有數據,所有員工編號都從1001開始編號。

6.基數轉換法
將十進制數X看作其他進制,比如十三進制,再按照十三進制數轉換成十進制數,提取其中若干爲作爲X的哈希值。一般取大於原來基數的數作爲轉換的基數,並且兩個基數應該是互素的。

例8,Hash(80127429)=(80127429)13=8*137+0*136+1*135+2*134+7*133+4*132+2*131+9=(502432641)10如果取中間三位作爲哈希值,得Hash(80127429)=432

爲了獲得良好的哈希函數,可以將幾種方法聯合起來使用,比如先變基,再摺疊或平方取中等等,只要散列均勻,就可以隨意拼湊。[5] ↑

7.除留餘數法
取關鍵字被某個不大於哈希表表長m的數p除後所得餘數爲哈希地址,即設定哈希函數爲 Hash(key)=key mod p (p≤m),其中,除數p稱作模。

除留餘數法不僅可以對關鍵字直接取模,也可以在摺疊、平方取中等運算後取模。對於除留餘數法求哈希地址,關鍵在於模p的選擇。使得數據元素集合中每一個關鍵字通過該哈希函數映射到內存單元的任意地址上的概率相等,從而儘可能減少發生哈希衝突的可能性。

理論研究表明,除留餘數法的模p取不大於表長且最接近表長m素數時效果最好,且p最好取1.1n~1.7n之間的一個素數(n爲存在的數據元素個數)。例如:當n=7時,p最好取11、13等素數。 又例圖(5):

表長m

8

16

32

64

128

256

512

1000

模p

7

13

31

61

127

251

503

997

由於除留餘數法的地址計算方法簡單,而且在許多情況下效果較好。[2]↑

例9,公司有236個員工,而員工編號介於1000到9999,除留餘數法就是員工編號除以數據個數236後,去餘數即爲數據的位置。編號5428員工的數據(編號5428除以236取餘數得0)放數據中的第一筆,編號3512員工數據(編號3512除以236取餘數得8)放數據中的第九筆…依次類推。

8.隨機乘數法
亦稱爲“乘餘取整法”。隨機乘數法使用一個隨機實數f,0≤f<1,乘積f*k的分數部分在0~1之間,用這個分數部分的值與n(哈希表的長度)相乘,乘積的整數部分就是對應的哈希值,顯然這個哈希值落在0~n-1之間。其表達公式爲:Hash(k)=「n*(f*k%1)」其中“f*k%1”表示f*k 的小數部分,即f*k%1=f*k-「f*k」[5] ↑

例10,對下列關鍵字值集合採用隨機乘數法計算哈希值,隨機數f=0.103149002 哈希表長度n=100得圖(6):

k

f*k

n*((f*k)的小數部分)

Hash(k)

319426

32948.47311

47.78411

47

718309

74092.85648

86.50448

86

629443

64926.41727

42.14427

42

919697

84865.82769

83.59669

83

此方法的優點是對n的選擇不很關鍵。通常若地址空間爲p位就是選n=2p.Knuth對常數f的取法做了仔細的研究,他認爲f取任何值都可以,但某些值效果更好。如f=(-1)/2=0.6180329…比較理想。[8] ↑

9.字符串數值哈希法
在很都情況下關鍵字是字符串,因此這樣對字符串設計Hash函數是一個需要討論的問題。下列函數是取字符串前10個字符來設計的哈希函數

Int Hash _ char (char *X)

{

int I ,sum

i=0;

while (i 10 && X[i])

Sum +=X[i++];

sum%=N; //N是記錄的條數

}

這種函數把字符串的前10個字符的ASCⅡ值之和對N取摸作爲Hash地址,只要N較小,Hash地址將較均勻分佈[0,N]區間內,因此這個函數還是可用的。對於N很大的情形,可使用下列函數

int ELFhash (char *key )

{

Unsigned long h=0,g;

whie (*key)

{

h=(h<<4)+ *key;

key++;

g=h & 0 xF0000000L;

if (g) h^=g>>24;

h & =~g;

}

h=h % N

return (h);

}

這個函數稱爲ELFHash(Exextable and Linking Format ,ELF,可執行鏈接格式)函數。它把一個字符串的絕對長度作爲輸入,並通過一種方式把字符的十進制值結合起來,對長字符串和短字符串都有效,這種方式產生的位置不可能不均勻分佈。[7] ↑

10.旋轉法
旋轉法是將數據的鍵值中進行旋轉。旋轉法通常並不直接使用在哈希函數上,而是搭配其他哈希函數使用。

例11,某學校同一個系的新生(小於100人)的學號前5位數是相同的,只有最後2位數不同,我們將最後一位數,旋轉放置到第一位,其餘的往右移。

新生學號

旋轉過程

旋轉後的新鍵值

5062101

5062101

1506210

5062102

5062102

2506210

5062103

5062103

3506210

5062104

5062104

4506210

5062105

5062105

5506210

                  如圖(7)

運用這種方法可以只輸入一個數值從而快速地查到有關學生的信息。[9] ↑

11.僞隨機數法
僞隨機數法是將利用數據的鍵值經過隨機數法的運算後的結果作爲數據存儲的位置。其公式如下(a和c爲質數):

Y=(a * Key + c)mod 數組的大小

例12,某公司的某女員工的編號是321547,現該公司共有107個女職工,我們取a=13,c=5則

Y=(13*321547+5)%107

=(4180111+5)%107

=54

則取54當作該員工數據存儲的位置。[10] ↑

小 結

有許多種不同的哈希函數設計方法,這裏主要討論幾種常用的不同類型關鍵字的希函數設計方法:直接定址法、數字分析法、摺疊法、平方取中法、減去法、基數轉換法、除留餘數法、隨機乘數法、字符串數值哈希法、僞隨機數法、旋轉法。

儘管哈希函數的構造方法有很多,但不同的方法適用於不同的情況。如:當鍵字是字符串時可以用字符串數值哈希法構造哈希函數;當關鍵字是整數類型時就可以用除留餘數法、直接定址法和數字分析法等設計哈希函數;而關鍵字是小數類型常用僞隨機數法來構造哈希函數等。

參 考 文 獻

[1]朱戰立編著.數據結構(C++語言描述) 北京:高等教育出版社,2004

[2]陳明編著.實用數據結構基礎 北京:清華大學出版社,2002

[3]嚴蔚敏等編著.數據結構及應用算法教程 北京:清華大學出版社,2000

[4]殷人昆等編著.數據結構:面向對象方法與C++描述 北京:清華大學出版社,1999

[5]熊嶽山等編著.數據結構:C++語言描述, 長沙:國防科技大學出版社,2002.2

[6]蘇光奎等編著. 數據結構導學。 北京:清華大學出版社,2002

[7]陳松喬等編著.算法與數據結構(C與C++描述) 北京:北方交通大學出版社 2002.8

[8]卓滋德克著.陳曙暉譯 數據結構與算法——C++ 北京:清華大學出版社, 2003

[9]王慶瑞編著.數據結構教程(C++語言描述) 北京:高等教育出版社,2002.8

[10]黃國瑜等編著.數據結構(Java語言版) 北京:清華大學出版社,2002

轉自http://wenku.baidu.com/view/61b121c06137ee06eff918c1.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章