日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

哈希函数的构造方法

發(fā)布時間:2023/12/31 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 哈希函数的构造方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

哈希函數(shù)的構(gòu)造方法

本文闡述了哈希函數(shù)的構(gòu)造方法有很多,但應(yīng)注意兩個原則:第一,函數(shù)值應(yīng)在1至記錄總數(shù)之間;第二,盡可能避免沖突。

設(shè)要存放的數(shù)據(jù)元素有n個,存放數(shù)據(jù)元素的內(nèi)存單元有m個,設(shè)計哈希函數(shù)的目標(biāo)就是要使通過哈希函數(shù)得到的n個數(shù)據(jù)元素的哈希地址盡可能均勻地分布在m個連續(xù)內(nèi)存單元上,同時使計算過程盡可能簡單以達到盡可能高的時間效率。

引 言
構(gòu)造哈希函數(shù)的方法很多。如何構(gòu)造一個“好”的哈希函數(shù)是很強的技術(shù)性和實踐性問題,這里的“好”指的是哈希函數(shù)構(gòu)造比較簡單,并且用此哈希函數(shù)產(chǎn)生的映射所發(fā)生的沖突可能性最小,換句話說一個好的哈希函數(shù)能將給定數(shù)據(jù)集合均勻地映射到給定的地址區(qū)間中。

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

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

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

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

地址

A1

A2

……

A99

A100

年齡

1

2

……

99

100

人數(shù)

980

800

……

495

107

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

2.數(shù)字分析法
2.1數(shù)字分析法是取數(shù)據(jù)元素關(guān)鍵字中某些取值較均勻的數(shù)字位作為哈希地址的方法。即當(dāng)關(guān)鍵字的位數(shù)很多時,可以通過對關(guān)鍵字的各位進行分析,丟掉分布不均勻的位,作為哈希值。它只適合于所有關(guān)鍵字值已知的情況。通過分析分布情況把關(guān)鍵字取值區(qū)間轉(zhuǎn)化為一個較小的關(guān)鍵字取值區(qū)間。

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

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

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

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

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

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

    例3,有一組關(guān)鍵字,對其各位編碼如下:

    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”出現(xiàn)8次r1=(8-8/10)2*1+(0-8/10)2*9=57.60

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

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

    ④位“0,4”各出現(xiàn)2次,“2,3,5,6”各出現(xiàn)1次

    ⑤位“7,8”各出現(xiàn)2次,“0,1,5,9”各出現(xiàn)1次

    r3 =r4 =r5 =5.60

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

    3.折疊法
    所謂折疊法是將關(guān)鍵字分割成位數(shù)相同的幾部分(最后一部分的位數(shù)可以不同),然后取這幾部分的疊加和(舍去進位),這方法稱為折疊法。這種方法適用于關(guān)鍵字位數(shù)較多,而且關(guān)鍵字中每一位上數(shù)字分布大致均勻的情況。

    折疊法中數(shù)位折疊又分為移位疊加和邊界疊加兩種方法,移位疊加是將分割后是每一部分的最低位對齊,然后相加;邊界疊加是從一端向另一端沿分割界來回折疊,然后對齊相加。

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

    移位疊加 邊界疊加8 9 1 8 9 11 1 9 9 1 13 3 1 3 3 11 0 8 8 0 1+ 1 1 0 + 1 1 0

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

    圖(2)由折疊法求哈希地址用移位疊加得到的哈希地址是559,而用邊界疊加所得到的哈希地址是44。如果關(guān)鍵字不是數(shù)值而是字符串,則可先轉(zhuǎn)化為數(shù)。轉(zhuǎn)化的辦法可以用ASCⅡ字符或字符的次序值。[3]↑

    4.平方取中法
    這是一種常用的哈希函數(shù)構(gòu)造方法。這個方法是先取關(guān)鍵字的平方,然后根據(jù)可使用空間的大小,選取平方數(shù)是中間幾位為哈希地址。

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

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

    關(guān)鍵字

    關(guān)鍵字的平方

    哈希函數(shù)值

    1234

    1522756

    227

    2143

    4592449

    924

    4132

    17073424

    734

    3214

    10329796

    297

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

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

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

    關(guān)鍵字

    機內(nèi)碼

    機內(nèi)碼的平方

    哈希地址

    ABC

    010203

    0104101209

    101

    BCD

    020304

    0412252416

    252

    CDE

    030405

    0924464025

    464

    DEF

    040506

    1640736036

    736

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

    下面給出平方取中法的哈希函數(shù)

    //平方取中法哈希函數(shù),結(jié)設(shè)關(guān)鍵字值32位的整數(shù)//哈希函數(shù)將返回key * key的中間10位Int Hash (int key){//計算key的平方Key * = key ;//去掉低11位Key>>=11;// 返回低10位(即key * key的中間10位)Return key %1024;}

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

    例7,公司有一百個員工,而員工的編號介于1001到1100,減去法就是員工編號減去1000后即為數(shù)據(jù)的位置。編號1001員工的數(shù)據(jù)在數(shù)據(jù)中的第一筆。編號1002員工的數(shù)據(jù)在數(shù)據(jù)中的第二筆…依次類推。從而獲得有關(guān)員工的所有信息,因為編號1000以前并沒有數(shù)據(jù),所有員工編號都從1001開始編號。

    6.基數(shù)轉(zhuǎn)換法
    將十進制數(shù)X看作其他進制,比如十三進制,再按照十三進制數(shù)轉(zhuǎn)換成十進制數(shù),提取其中若干為作為X的哈希值。一般取大于原來基數(shù)的數(shù)作為轉(zhuǎn)換的基數(shù),并且兩個基數(shù)應(yīng)該是互素的。

    例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

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

    7.除留余數(shù)法
    取關(guān)鍵字被某個不大于哈希表表長m的數(shù)p除后所得余數(shù)為哈希地址,即設(shè)定哈希函數(shù)為 Hash(key)=key mod p (p≤m),其中,除數(shù)p稱作模。

    除留余數(shù)法不僅可以對關(guān)鍵字直接取模,也可以在折疊、平方取中等運算后取模。對于除留余數(shù)法求哈希地址,關(guān)鍵在于模p的選擇。使得數(shù)據(jù)元素集合中每一個關(guān)鍵字通過該哈希函數(shù)映射到內(nèi)存單元的任意地址上的概率相等,從而盡可能減少發(fā)生哈希沖突的可能性。

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

    表長m

    8

    16

    32

    64

    128

    256

    512

    1000

    模p

    7

    13

    31

    61

    127

    251

    503

    997

    由于除留余數(shù)法的地址計算方法簡單,而且在許多情況下效果較好。[2]↑

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

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

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

    k

    f*k

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

    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

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

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

    Int Hash _ char (char *X)

    {

    int I ,sum

    i=0;

    while (i 10 && X[i])

    Sum +=X[i++];

    sum%=N; //N是記錄的條數(shù)

    }

    這種函數(shù)把字符串的前10個字符的ASCⅡ值之和對N取摸作為Hash地址,只要N較小,Hash地址將較均勻分布[0,N]區(qū)間內(nèi),因此這個函數(shù)還是可用的。對于N很大的情形,可使用下列函數(shù)

    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);

    }

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

    10.旋轉(zhuǎn)法
    旋轉(zhuǎn)法是將數(shù)據(jù)的鍵值中進行旋轉(zhuǎn)。旋轉(zhuǎn)法通常并不直接使用在哈希函數(shù)上,而是搭配其他哈希函數(shù)使用。

    例11,某學(xué)校同一個系的新生(小于100人)的學(xué)號前5位數(shù)是相同的,只有最后2位數(shù)不同,我們將最后一位數(shù),旋轉(zhuǎn)放置到第一位,其余的往右移。

    新生學(xué)號

    旋轉(zhuǎn)過程

    旋轉(zhuǎn)后的新鍵值

    5062101

    5062101

    1506210

    5062102

    5062102

    2506210

    5062103

    5062103

    3506210

    5062104

    5062104

    4506210

    5062105

    5062105

    5506210

    如圖(7)

    運用這種方法可以只輸入一個數(shù)值從而快速地查到有關(guān)學(xué)生的信息。[9] ↑

    11.偽隨機數(shù)法
    偽隨機數(shù)法是將利用數(shù)據(jù)的鍵值經(jīng)過隨機數(shù)法的運算后的結(jié)果作為數(shù)據(jù)存儲的位置。其公式如下(a和c為質(zhì)數(shù)):

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

    例12,某公司的某女員工的編號是321547,現(xiàn)該公司共有107個女職工,我們?nèi)=13,c=5則

    Y=(13*321547+5)%107

    =(4180111+5)%107

    =54

    則取54當(dāng)作該員工數(shù)據(jù)存儲的位置。[10] ↑

    小 結(jié)

    有許多種不同的哈希函數(shù)設(shè)計方法,這里主要討論幾種常用的不同類型關(guān)鍵字的希函數(shù)設(shè)計方法:直接定址法、數(shù)字分析法、折疊法、平方取中法、減去法、基數(shù)轉(zhuǎn)換法、除留余數(shù)法、隨機乘數(shù)法、字符串?dāng)?shù)值哈希法、偽隨機數(shù)法、旋轉(zhuǎn)法。

    盡管哈希函數(shù)的構(gòu)造方法有很多,但不同的方法適用于不同的情況。如:當(dāng)鍵字是字符串時可以用字符串?dāng)?shù)值哈希法構(gòu)造哈希函數(shù);當(dāng)關(guān)鍵字是整數(shù)類型時就可以用除留余數(shù)法、直接定址法和數(shù)字分析法等設(shè)計哈希函數(shù);而關(guān)鍵字是小數(shù)類型常用偽隨機數(shù)法來構(gòu)造哈希函數(shù)等。

    參 考 文 獻

    [1]朱戰(zhàn)立編著.數(shù)據(jù)結(jié)構(gòu)(C++語言描述) 北京:高等教育出版社,2004

    [2]陳明編著.實用數(shù)據(jù)結(jié)構(gòu)基礎(chǔ) 北京:清華大學(xué)出版社,2002

    [3]嚴蔚敏等編著.數(shù)據(jù)結(jié)構(gòu)及應(yīng)用算法教程 北京:清華大學(xué)出版社,2000

    [4]殷人昆等編著.數(shù)據(jù)結(jié)構(gòu):面向?qū)ο蠓椒ㄅcC++描述 北京:清華大學(xué)出版社,1999

    [5]熊岳山等編著.數(shù)據(jù)結(jié)構(gòu):C++語言描述, 長沙:國防科技大學(xué)出版社,2002.2

    [6]蘇光奎等編著. 數(shù)據(jù)結(jié)構(gòu)導(dǎo)學(xué)。 北京:清華大學(xué)出版社,2002

    [7]陳松喬等編著.算法與數(shù)據(jù)結(jié)構(gòu)(C與C++描述) 北京:北方交通大學(xué)出版社 2002.8

    [8]卓滋德克著.陳曙暉譯 數(shù)據(jù)結(jié)構(gòu)與算法——C++ 北京:清華大學(xué)出版社, 2003

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

    [10]黃國瑜等編著.數(shù)據(jù)結(jié)構(gòu)(Java語言版) 北京:清華大學(xué)出版社,2002

    轉(zhuǎn)自http://wenku.baidu.com/view/61b121c06137ee06eff918c1.htm

    總結(jié)

    以上是生活随笔為你收集整理的哈希函数的构造方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。