程序員常說的「哈希表」是個什么鬼?
今天聊聊「哈希表」,「哈希表」主要作用在于高效查找。
在編程實現中,常常面臨著兩個問題:存儲和查找,存儲和查找的效率往往決定了整個程序的效率。
腦補下,你在家里忘記了指甲刀放在哪里,通常要在你家所有抽屜中順序尋找,直到找到,最差情況下,有N個抽屜,你就要打開N個抽屜。這種存儲方式叫數組,查找方法稱為「遍歷」。
腦補下,你是一個整理控,所有物品必須分門別類放入整理箱,再將整理箱編號,比如1號放入針線,2號放入證件,3號放入細軟。這種存儲和查找方式稱為「哈?!?,如果這個時候要查找護照,你不許要再翻所有抽屜,直接可在2號整理箱中獲取,通常只用一次查找即可,如何編號整理箱,稱為哈希算法。
同樣是查找,差距怎么那么大涅~,假設我們有100億條數據記錄,那差距就變得明顯,遍歷需要查找最多100億次,最少1次,哈希只需1次。
讓我們正式介紹哈希和哈希算法,哈希也稱散列,哈希表是一種與數組、鏈表等不同的數據結構,與他們需要不斷的遍歷比較來查找的辦法,哈希表設計了一個映射關系f(key)= address,根據key來計算存儲地址address,這樣可以1次查找,f既是存儲數據過程中用來指引數據存儲到什么位置的函數,也是將來查找這個位置的算法,叫做哈希算法。
讓我們舉個例子,比如下面這幾個人物,按數組存儲:
這樣我要找到大胸姐的電話號碼,需要順序查找對比整個數組,第一個余罪,不是,第二個不是,第三個不是,直到第四個找到大胸姐。
如果以hash存儲呢?首先讓我們來看看如何設計哈希算法,哈希算法可以隨意設計,教科書上一般會說以下幾種方法:直接定址發,平方取中法,除數取余法,哈希算法的本質上是計算一個數字,如果用這幾種方法講解會稍顯晦澀,我們假設我們的哈希算法是取姓名的首字母。所以f(余罪) = y, f(傅老大) = f,f(沈嘉文) = s,f(大胸姐) = d。
構建的hash表如下:
我們看到他們分別以姓名首字母的位置插入到這一張表格中,這樣我們構建了這樣一個Key-Value表格,此表就是哈希表,也稱為Hash Table。未來,當我們要查找余罪的時候,通過計算,余罪在y位置,可以通過1次查找,找到這條記錄,也即手機號。
這個時候有客官問了,那以首字母為哈希函數的話,應該有很多比如以y的姓名啊,這個時候就不是一次查找了吧,其實有很多條記錄都映射到一個位置上,稱為哈希沖突。
哈希沖突是跟哈希函數的設計正相關的,你的隨機性越大,那么產生哈希沖突的可能性越小,在小概率下,如果還有沖突怎么辦,這個時候要做些有損的設計,比如如果有兩個首字母為y的姓名,那么可以接到余罪的后面,當查找的時候,需要先查找到y,然后再順序查找,如圖所示:
還有一些解決哈希沖突的辦法叫「哈希再哈?!?,也就是針對第一次哈希的結果再進行一次hash來減小沖突的概率。
這就是Hash表,首先Ta是一種數據結構,是一種效率極高的查找方式,哈希表的核心在于哈希函數的設計,哈希沖突了不要緊,我們要增加隨機性以及對沖突進行適當的有損化的處理。
#專欄作家#
給產品經理講技術,微信公眾號(pm_teacher),人人都是產品經理專欄作家。資深程序猿,專注客戶端開發若干年,對前端、后臺技術略懂,熱衷于對新的科技領域的探索。
本文原創發布于人人都是產品經理。未經許可,禁止轉載。
題圖來自PEXELS,基于CC0協議
我做了一個[哈希表的可視化頁面](https://gallery.selfboot.cn/zh/algorithms/hashtable),采用網格布局模擬哈希表的內部結構。
每個格子代表一個哈希桶,格子的顏色深淺直觀地反映了該桶中存儲的元素數量,顏色越深表示包含的元素越多??梢渣c擊任意格子,系統會顯示一個彈窗,展示該桶中存儲的所有鍵值對詳細信息。
在進行插入、查找、刪除等操作時,系統會通過高亮效果顯示當前操作涉及的桶,幫助理解哈希表的工作原理。
呵呵噠
以前上課的時候老師叨叨了半天不懂的,在你這里看了幾分鐘的文章就懂了,哎……
我的天。。我們上數據結構的老師上來直接講哈希表是怎么做的,怎么做那種將一個數據和其哈希值(位置?)對應。根本沒講哈希算法是用來查找的。。
你確定有在聽課。。。
??