日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

纸上谈兵: 哈希表 (hash table)

發(fā)布時(shí)間:2025/7/14 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 纸上谈兵: 哈希表 (hash table) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉(zhuǎn)載,也請(qǐng)保留這段聲明。謝謝!

?

HASH

哈希表(hash table)是從一個(gè)集合A到另一個(gè)集合B的映射(mapping)。映射是一種對(duì)應(yīng)關(guān)系,而且集合A的某個(gè)元素只能對(duì)應(yīng)集合B中的一個(gè)元素。但反過來,集合B中的一個(gè)元素可能對(duì)應(yīng)多個(gè)集合A中的元素。如果B中的元素只能對(duì)應(yīng)A中的一個(gè)元素,這樣的映射被稱為一一映射。這樣的對(duì)應(yīng)關(guān)系在現(xiàn)實(shí)生活中很常見,比如:

A? -> B

-> 身份證號(hào)

日期 -> 星座

?

上面兩個(gè)映射中, -> 身份證號(hào)一一映射的關(guān)系。在哈希表中,上述對(duì)應(yīng)過程稱為hashing。A中元素a對(duì)應(yīng)B中元素b,a被稱為鍵值(key),b被稱為a的hash值(hash value)。

?韋小寶的hash值

?

映射在數(shù)學(xué)上相當(dāng)于一個(gè)函數(shù)f(x):A->B。比如 f(x) = 3x + 2。哈希表的核心是一個(gè)哈希函數(shù)(hash function),這個(gè)函數(shù)規(guī)定了集合A中的元素如何對(duì)應(yīng)到集合B中的元素。比如:

A: 三位整數(shù)??? hash(x) = x % 10? ? B: 一位整數(shù)

104???????????? ? ? ? ? ?? ?? ??? 4

876???????????? ? ? ? ? ? ? ? ? ? 6

192??????????????? ? ? ? ? ? ? ?? 2

上述對(duì)應(yīng)中,哈希函數(shù)表示為hash(x) = x % 10。也就是說,給一個(gè)三位數(shù),我們取它的最后一位作為該三位數(shù)的hash值。

?

哈希表在計(jì)算機(jī)科學(xué)中應(yīng)用廣泛。比如:

Ethernet中的FCS:參看小喇叭開始廣播 (以太網(wǎng)與WiFi協(xié)議)

IP協(xié)議中的checksum:參看我盡力 (IP協(xié)議詳解)

git中的hash值:參看版本管理三國(guó)志

上述應(yīng)用中,我們用一個(gè)hash值來代表鍵值。比如在git中,文件內(nèi)容為鍵值,并用SHA算法作為hash function,將文件內(nèi)容對(duì)應(yīng)為固定長(zhǎng)度的字符串(hash值)。如果文件內(nèi)容發(fā)生變化,那么所對(duì)應(yīng)的字符串就會(huì)發(fā)生變化。git通過比較較短的hash值,就可以知道文件內(nèi)容是否發(fā)生變動(dòng)。

?

再比如計(jì)算機(jī)的登陸密碼,一般是一串字符。然而,為了安全起見,計(jì)算機(jī)不會(huì)直接保存該字符串,而是保存該字符串的hash值(使用MD5、SHA或者其他算法作為hash函數(shù))。當(dāng)用戶下次登陸的時(shí)候,輸入密碼字符串。如果該密碼字符串的hash值與保存的hash值一致,那么就認(rèn)為用戶輸入了正確的密碼。這樣,就算黑客闖入了數(shù)據(jù)庫(kù)中的密碼記錄,他能看到的也只是密碼的hash值。上面所使用的hash函數(shù)有很好的單向性:很難從hash值去推測(cè)鍵值。因此,黑客無法獲知用戶的密碼。

(之前有報(bào)道多家網(wǎng)站用戶密碼泄露的時(shí)間,就是因?yàn)檫@些網(wǎng)站存儲(chǔ)明文密碼,而不是hash值,見多家網(wǎng)站卷入CSDN泄密事件 明文密碼成爭(zhēng)議焦點(diǎn))

?

注意,hash只要求從A到B的對(duì)應(yīng)為一個(gè)映射,它并沒有限定該對(duì)應(yīng)關(guān)系為一一映射。因此會(huì)有這樣的可能:兩個(gè)不同的鍵值對(duì)應(yīng)同一個(gè)hash值。這種情況叫做hash碰撞(hash collision)。比如網(wǎng)絡(luò)協(xié)議中的checksum就可能出現(xiàn)這種狀況,即所要校驗(yàn)的內(nèi)容與原文并不同,但與原文生成的checksum(hash值)相同。再比如,MD5算法常用來計(jì)算密碼的hash值。已經(jīng)有實(shí)驗(yàn)表明,MD5算法有可能發(fā)生碰撞,也就是不同的明文密碼生成相同的hash值,這將給系統(tǒng)帶來很大的安全漏洞。(參考hash collision)

?

HASH與搜索

hash表被廣泛的用于搜索。設(shè)定集合A為搜索對(duì)象,集合B為存儲(chǔ)位置,利用hash函數(shù)將搜索對(duì)象與存儲(chǔ)位置對(duì)應(yīng)起來。這樣,我們就可以通過一次hash,將對(duì)象所在位置找到。一種常見的情形是,將集合B設(shè)定在數(shù)組下標(biāo)。由于數(shù)組可以根據(jù)數(shù)組下標(biāo)進(jìn)行隨機(jī)存取(random access,算法復(fù)雜度為1),所以搜索操作將取決于hash函數(shù)的復(fù)雜程度。

?

比如我們以人名(字符串)為鍵值,以數(shù)組下標(biāo)為hash值。每個(gè)數(shù)組元素中存儲(chǔ)有一個(gè)指針,指向記錄 (有人名和電話號(hào)碼)。

?

下面是一個(gè)簡(jiǎn)單的hash函數(shù):

#define HASHSIZE 1007
/* By Vamei
* hash function
*/ int hash(char *p) {int value=0;while((*p) != '\0') {value = value + (int) (*p); // convert char to int, and sump++;}return (value % HASHSIZE); // won's exceed HASHSIZE }

hash value of "Vamei": 498

hash value of "Obama": 480

?

我們可以建立一個(gè)HASHSIZE大小的數(shù)組records,用于儲(chǔ)存記錄。HASHSIZE被選擇為質(zhì)數(shù),以便hash值能更加均勻的分布。在搜索"Vamei"的記錄時(shí),可以經(jīng)過hash,得到hash值498,再直接讀取records[498],就可以讀取記錄了。

(666666是Obama的電話號(hào)碼,111111是Vamei的電話號(hào)碼。純屬杜撰,請(qǐng)勿當(dāng)真)

hash搜索

如果不采用hash,而只是在一個(gè)數(shù)組中搜索的話,我們需要依次訪問每個(gè)記錄,直到找到目標(biāo)記錄,算法復(fù)雜度為n。我們可以考慮一下為什么會(huì)有這樣的差別。數(shù)組雖然可以隨機(jī)讀取,但數(shù)組下標(biāo)是隨機(jī)的,它與元素值沒有任何關(guān)系,所以我們要逐次訪問各個(gè)元素。通過hash函數(shù),我們限定了每個(gè)下標(biāo)位置可能存儲(chǔ)的元素。這樣,我們利用鍵值和hash函數(shù),就可以具備相當(dāng)?shù)南闰?yàn)知識(shí),來選擇適當(dāng)?shù)南聵?biāo)進(jìn)行搜索。在沒有hash碰撞的前提下,我們只需要選擇一次,就可以保證該下標(biāo)指向的元素是我們想要的元素。

?

沖突

hash函數(shù)需要解決hash沖突的問題。比如,上面的hash函數(shù)中,"Obama"和"Oaamb"有相同的hash值,發(fā)生沖突。我們?nèi)绾谓鉀Q呢?

?

一個(gè)方案是將發(fā)生沖突的記錄用鏈表儲(chǔ)存起來,讓hash值指向該鏈表,這叫做open hashing:

open hashing

我們?cè)谒阉鞯臅r(shí)候,先根據(jù)hash值找到鏈表,再根據(jù)key值遍歷搜索鏈表,直到找到記錄。我們可以用其他數(shù)據(jù)結(jié)構(gòu)代替鏈表。

?

open hashing需要使用指針。我們有時(shí)候想要避免使用指針,以保持隨機(jī)存儲(chǔ)的優(yōu)勢(shì),所以采用closed hashing的方式來解決沖突。

closed hashing

這種情況下,我們將記錄放入數(shù)組。當(dāng)有沖突出現(xiàn)的時(shí)候,我們將沖突記錄放在數(shù)組中依然閑置的位置,比如圖中Obama被插入后,隨后的Oaamb也被hash到480位置。但由于480被占據(jù),Oaamb探測(cè)到下一個(gè)閑置位置(通過將hash值加1),并記錄。

closed hashing的關(guān)鍵在如何探測(cè)下一個(gè)位置。上面是將hash值加1。但也可以有其它的方式。概括的說,在第i次的時(shí)候,我們應(yīng)該探測(cè)POSITION(i)=(h(x) + f(i)) % HASHSIZE的位置。上面將hash值加1的方式,就相當(dāng)于設(shè)定f(i) = 1當(dāng)我們?cè)谒阉鞯臅r(shí)候,就可以利用POSITION(i),依次探測(cè)記錄可能出現(xiàn)的位置,直到找到記錄。

(f(i)的選擇會(huì)帶來不同的結(jié)果,這里不再深入)

如果數(shù)組比較滿,那么closed hashing需要進(jìn)行許多次探測(cè)才能找到空位。這樣將大大減小插入和搜索的效率。這種情況下,需要增大HASHSIZE,并將原來的記錄放入到新的比較大的數(shù)組中。這樣的操作稱為rehashing

?

總結(jié)

hash表,搜索

hash沖突, open hashing, closed hashing

?

歡迎繼續(xù)閱讀“紙上談兵: 算法與數(shù)據(jù)結(jié)構(gòu)”系列。

?

轉(zhuǎn)載于:https://www.cnblogs.com/vamei/archive/2013/03/24/2970339.html

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的纸上谈兵: 哈希表 (hash table)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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