算法入門(mén):Hash

什么是Hash算法:#####

簡(jiǎn)單的說(shuō)疾瓮,hash算法就是將字符串轉(zhuǎn)化為數(shù)字的算法俺祠。

用一個(gè)例子說(shuō)Hash的優(yōu)勢(shì)#####

試想如果我們對(duì)一個(gè)數(shù)組進(jìn)行Query瓦堵,這個(gè)數(shù)組里困鸥,每一個(gè)元素都是一個(gè)字符串嗅蔬。我們知道數(shù)組最快的檢索辦法是通過(guò)數(shù)組的下標(biāo)進(jìn)行檢索,但是對(duì)于這種場(chǎng)景疾就,我們無(wú)能為力澜术,只能從頭查到尾,從而查詢(xún)出目標(biāo)元素猬腰。


Paste_Image.png

假設(shè)鸟废,我要找gaofei,那就需要遍歷整個(gè)數(shù)組姑荷,十分的低效盒延。這樣最壞情況下時(shí)間復(fù)雜度是O(n)的缩擂,但是數(shù)組的查詢(xún)時(shí)間復(fù)雜度是O(1)的(下標(biāo)查詢(xún)),那有沒(méi)有一種方法能達(dá)到O(1)的時(shí)間復(fù)雜度呢添寺?有胯盯!那就是用 Hash。
我們需要達(dá)到O(1)的時(shí)間復(fù)雜度计露,那無(wú)疑使用數(shù)組的下標(biāo)查找博脑。那么我們就需要將存儲(chǔ)的元素轉(zhuǎn)化為數(shù)組的下標(biāo)。
那怎么設(shè)計(jì)hash函數(shù)呢票罐?我們用一種最笨的方法叉趣,將所有字符串中的字符轉(zhuǎn)化為數(shù)字后相加。那ok该押,我們簡(jiǎn)單的實(shí)現(xiàn)下君账。
zhangsan=>hash()=>858
lisi=>hash()=>433
wanger=>hash()=>644
wangwu=>hash()=>665
zhangsi=>hash()=>756
gaofei=>hash()=>619
這樣,我們就計(jì)算出來(lái)了每一個(gè)字符串對(duì)應(yīng)的數(shù)字映射了沈善,我們叫這個(gè)數(shù)字為hash值乡数,接下來(lái)我們?cè)俜诺綌?shù)組里:

Paste_Image.png

上圖中數(shù)組的下標(biāo)就是字符串對(duì)應(yīng)的數(shù)字值。這下我們查找gaofei就很容易了闻牡,首先我們根據(jù)hash函數(shù)計(jì)算出gaofei的位置為619净赴,然后去數(shù)組的619中找到gaofei,這樣時(shí)間復(fù)雜度就是O(1)啦罩润。

hash沖突(拉鏈法):#####

但是上面的實(shí)現(xiàn)是存在一個(gè)問(wèn)題的玖翅,如果還有一個(gè)元素叫feigao會(huì)怎么樣?
我們首先計(jì)算下feigao的hash值割以,計(jì)算結(jié)果竟然和gaofei一樣金度,也是619。這下產(chǎn)生了Hash沖突了严沥,怎么辦猜极?619已經(jīng)有g(shù)aofei了,feigao放在哪消玄?所以接下來(lái)我們只能改變數(shù)組的結(jié)構(gòu)了跟伏,怎么改變?我們將數(shù)組內(nèi)的元素改變?yōu)橐粋€(gè)鏈表翩瓜,這樣就能裝下足夠多的元素了受扳。這樣就能解決hash沖突的問(wèn)題了:

Paste_Image.png

如上圖,我們將沖突的元素變?yōu)榱随湵斫Y(jié)構(gòu)兔跌,這樣我們就能把feigao也放在了這個(gè)table結(jié)構(gòu)里面勘高,其實(shí)這個(gè)數(shù)據(jù)結(jié)構(gòu)就叫做Hash表(HashTable)。
我們?cè)跈z索的時(shí)候可以這樣檢索

Paste_Image.png

找到gaofei后,我們便可以遍歷鏈表华望,找到feigao了层亿。是不是很開(kāi)森?

怎樣壓縮hash表#####

但是立美,問(wèn)題又來(lái)了匿又,上面的數(shù)組好像不是很連續(xù)啊,從433直接跳到了619.中間的數(shù)組都浪費(fèi)了啊!!!建蹄。其實(shí)也不能說(shuō)是浪費(fèi)碌更,只不過(guò)暫時(shí)沒(méi)有用啊,如果沒(méi)有對(duì)應(yīng)的元素出現(xiàn)洞慎,就這樣一直浪費(fèi)著痛单?顯然是不可取的。那我們想辦法壓縮下這個(gè)數(shù)組劲腿。
其實(shí)很簡(jiǎn)答旭绒,只要減小hash值就行了嘛,那么我們對(duì)hash值取模焦人,這樣就能保證所有的hash值落在模值之內(nèi)了挥吵。
但是對(duì)于取模的運(yùn)算計(jì)算機(jī)通常用位運(yùn)算是更快的,例如java的HashMap的默認(rèn)容量是16花椭,每次擴(kuò)容之后也都維持2^n,為什么呢忽匈?
對(duì)于取模運(yùn)算hashMap是這樣實(shí)現(xiàn)的hashcode& (length-1)。如果length為16矿辽,那么正好是hashcode&15丹允,例如feigao這個(gè)計(jì)算吧:
hash值:619 => ...0001001101011
length-1:15 => ...0000000001111
二者做與運(yùn)算結(jié)果為:...000000001011 => 11(十進(jìn)制)
其實(shí)可以口算一下結(jié)果為38余11(注意這里是除16而不是15)。同理對(duì)于32也是一樣的袋倔。但是這里有一個(gè)很著名的問(wèn)題雕蔽,就是因?yàn)閿?shù)字的不均勻會(huì)導(dǎo)致hash值的二進(jìn)制數(shù)末尾都是1的這種場(chǎng)景。這種場(chǎng)景會(huì)導(dǎo)致很多的值集中在最后一個(gè)數(shù)組元素宾娜,從而分布不均勻批狐。解決方案是對(duì)hash值進(jìn)行重新計(jì)算hash。這種機(jī)制比較復(fù)雜碳默。至今沒(méi)搞懂贾陷。
這里主要是考慮這樣設(shè)計(jì)主要考慮計(jì)算速度會(huì)十分的快,根據(jù)不同實(shí)現(xiàn)這個(gè)容量也是不固定的嘱根,這里只是以java的HashMap為例。

用幾個(gè)例子說(shuō)一下HashTable的用處:#####
Case1:兩文件找出重復(fù)的元素#####

問(wèn)題是這樣的巷懈,有兩個(gè)文件该抒,文件中有一些短字符串,字符串個(gè)數(shù)分別為n顶燕。它們是有重復(fù)的字符串凑保,現(xiàn)在需要找出所有重復(fù)的字符串冈爹。
首先我們考慮最笨的方法,遍歷文件1中的每個(gè)元素欧引,取出每一個(gè)元素分別去文件2中進(jìn)行查找频伤,這樣的時(shí)間復(fù)雜度為O(n^2)
接下來(lái)我們使用HashTable,我們遍歷文件1中的元素和文件2中的元素芝此,放入HashTable中憋肖,對(duì)于重復(fù)的字符串我們做計(jì)數(shù)處理:

Paste_Image.png

接下來(lái)遍歷整個(gè)列表,找出所有個(gè)數(shù)大于1的即為重復(fù)的元素婚苹。

Case2:兩文件找出出現(xiàn)次數(shù)最多的元素#####

和上面是同理的岸更,但是在遍歷的時(shí)候需要找計(jì)數(shù)最大的元素,即為出現(xiàn)次數(shù)最多的元素膊升。

Case3:路由算法#####

在一個(gè)多線(xiàn)程處理數(shù)據(jù)的場(chǎng)景下怎炊,我們需要將一個(gè)數(shù)據(jù)集分給不同的處理線(xiàn)程,同時(shí)要保證廓译,相同的元素需要分到相同的處理線(xiàn)程上去评肆,那么我們?cè)趺刺幚砟兀?br> 其實(shí)這個(gè)就是一個(gè)很典型的Hash值應(yīng)用場(chǎng)景,對(duì)于很多的計(jì)算引擎默認(rèn)都是用hash算法去解決這個(gè)問(wèn)題非区。因?yàn)橄嗤氐腍ash值相同糟港,那么我們可以取hash之后進(jìn)行模運(yùn)算,運(yùn)算結(jié)果分配到不同的線(xiàn)程:

Paste_Image.png
Hash算法的要點(diǎn)#####

在設(shè)計(jì)Hash算法的時(shí)候院仿。一定要保證相同字符串產(chǎn)生的Hash值相同秸抚,同時(shí)要盡量的減小Hash沖突的發(fā)生(雖然避免不了)。這樣才是一個(gè)好的hash算法歹垫。目前剥汤,MurmurHash是一種沖突率最低的Hash算法。如果有需要排惨,可以?xún)?yōu)先考慮此算法吭敢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市暮芭,隨后出現(xiàn)的幾起案子鹿驼,更是在濱河造成了極大的恐慌,老刑警劉巖辕宏,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畜晰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡瑞筐,警方通過(guò)查閱死者的電腦和手機(jī)凄鼻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人块蚌,你說(shuō)我怎么就攤上這事闰非。” “怎么了峭范?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵财松,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我纱控,道長(zhǎng)辆毡,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任其徙,我火速辦了婚禮胚迫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘唾那。我一直安慰自己访锻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布闹获。 她就那樣靜靜地躺著期犬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪避诽。 梳的紋絲不亂的頭發(fā)上龟虎,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音沙庐,去河邊找鬼鲤妥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拱雏,可吹牛的內(nèi)容都是我干的棉安。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼铸抑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼贡耽!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鹊汛,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蒲赂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后刁憋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體滥嘴,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年职祷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了氏涩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片届囚。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡有梆,死狀恐怖是尖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情泥耀,我是刑警寧澤饺汹,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站痰催,受9級(jí)特大地震影響兜辞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜夸溶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一逸吵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缝裁,春花似錦扫皱、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至粹污,卻和暖如春段多,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背壮吩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工进苍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鸭叙。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓觉啊,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親递雀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子柄延,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 第一章 Nginx簡(jiǎn)介 Nginx是什么 沒(méi)有聽(tīng)過(guò)Nginx?那么一定聽(tīng)過(guò)它的“同行”Apache吧缀程!Ngi...
    JokerW閱讀 32,642評(píng)論 24 1,002
  • 作者:July搜吧、wuliming、pkuoliver 說(shuō)明:本文分為三部分內(nèi)容杨凑,第一部分為一道百度面試題Top K...
    cyj_ya閱讀 800評(píng)論 0 0
  • 四 情不知所起 不知道為什么滤奈,蕭桐擋在林曉菲前面的那一幕在林曉菲心里演了一遍又一...
    小魚(yú)兒的寫(xiě)字臺(tái)閱讀 213評(píng)論 1 7
  • (一)only 修飾誰(shuí),就放誰(shuí)前面 正選A 正選C (二)Ving放句首表示主動(dòng) 與主語(yǔ)搭配撩满,選A (三)Ved放...
    Emily爺閱讀 311評(píng)論 0 0
  • 昨天中午,飯后昭躺,本來(lái)很瞌睡的忌锯,看完了今日說(shuō)法,慣性的要小睡會(huì)兒领炫,突然的偶垮,想起老師囑咐過(guò)要求看看《當(dāng)幸福來(lái)敲...
    a85d99ff3e56閱讀 411評(píng)論 0 0