編程基礎篇 · 哈希與緩存:空間換時間

哈希表:為什麼它找東西快到不講理

仲記唔記得第一課嗰條伏筆?「查會員名單」的版本 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 在千萬在綫用戶裏瞬間找到你的會話——靠的不是翻名單。

✅ 這一課想和你分享的