程式設計基礎篇 · 雜湊與快取:空間換時間

雜湊表:為什麼它找東西快到不講理

還記得第一課埋下的那條伏筆嗎?「查會員名單」的版本 B 用了一行 set.has(user),名單從 100 人漲到 1000 萬人,耗時紋絲不動。當時說好第五課揭底——今天就把這個「直達」的魔術拆給你看:它根本不翻,它是算出來的。

揭底時刻 · 它不翻,它靠算

回到收納的比喻:大抽屜找東西要挨個翻,是因為你不知道東西在哪。雜湊表的思路徹底反過來——放進去的那一刻,就用一條固定的公式算出它該放在幾號桶;要找的時候,用同一條公式再算一遍,直接開那個桶。這條公式就叫雜湊函式,它是一張「定位公式」:不用翻,一步算出在哪。

動手玩 · 親手把 key 塞進桶

下面是 8 個編號 0 到 7 的桶,和 6 個等著入住的名字。點一個名字,看它怎麼三步進桶:先把每個字變成電腦裡的編碼數字並求和,再對 8 求餘(因為只有 8 個桶),最後飛進算出來的那個桶。留意:全程沒有「挨個對比」這個動作,位置完全是算出來的。

雜湊函式(定位公式):把名字變數字 → 對 8 求餘 = 桶號
 
 
 
點上面的名字開始 · 每個名字只需入住一次
為什麼找的時候一樣快?因為找和放用的是同一條公式。你問「麗麗在不在名單裡?」,雜湊表不翻名單,而是當場再算一遍:麗麗 → 40058 → 對 8 求餘 = 2 號桶,直接開 2 號桶看一眼。名單有 6 個人是這樣,有 600 萬人還是這樣——算式的耗時和人數無關,這就是「快到不講理」的全部秘密。
意外情況 · 兩個名字撞進同一個桶

你可能已經發現了:阿芳和麗麗算出來都是 2 號桶!這叫雜湊碰撞——桶就 8 個,名字千千萬,撞桶遲早發生。那該怎麼辦?最常用的辦法樸素得可愛:在桶裡掛一條小鏈,後來的排在鏈上(術語叫「鏈地址法」)。按順序點下面三個按鈕,留意查詢時翻了幾次。

 
 
撞桶了也只翻了 2 次。直達 2 號桶(不算翻),鏈上先看到阿芳(第 1 次),再看到麗麗(第 2 次)——比把 6 個名字全翻一遍還是快得多。當然,如果桶太少、鏈越掛越長,雜湊表會自己加桶重排(擴容):比如從 8 個桶變 16 個桶,把所有名字用新公式重新算一遍位置,讓每條鏈重新變短。這就是「空間換時間」——多花點桶,換回直達的速度。
終極對決 · 翻一遍 vs 直達

現在把資料量拉大,讓兩種找法正面賽跑。選一個資料量,點開跑。留意右邊的計數器:不管左邊翻到天荒地老,它永遠停在 1-2 次。

資料量:
🗄 翻一遍(線性查詢)
翻找 0 次
 
🗃 直達(雜湊查詢)
翻找 0 次
 
動畫按比例放慢了,真實差距只會更誇張
它在 AI 世界的真身

雜湊表可能是你每天被服務次數最多的結構——只是它總躲在幕後。下面四個場景,背後全是同一招「算出位置,一步直達」。

🧰

Set 與字典

第一課版本 B 的 Set、Python 的 dict、JS 的 Map——語言裡所有「按 key 取值」的容器,肚子裡都是雜湊表。

🔑

快取的鍵

快取要在毫秒內回答「這個問題算過嗎」,靠的就是把問題雜湊成 key 直達查詢——下一課的主角。

🧹

去重

訓練語料去重、爬蟲判斷「這個網頁抓過沒」,都是把內容雜湊後進 Set 一查——不然億級資料兩兩對比要算到宇宙熱寂。

🎫

session 查詢

你每次開啟 ChatGPT,伺服器拿著 session id 在千萬線上使用者裡瞬間找到你的會話——靠的不是翻名單。

✅ 這一課想和你分享的