哈希表:为什么它找东西快到不讲理
还记得第一课的伏笔吗?「查会员名单」的版本 B 用了一行 set.has(user),名单从 100 人涨到 1000 万人,耗时纹丝不动。当时说好第五课揭底——今天就把这个「直达」的魔术拆给你看:它根本不翻,它是算出来的。
回到收纳的比喻:大抽屉找东西要挨个翻,是因为你不知道东西在哪。哈希表的思路彻底反过来——放进去的那一刻,就用一条固定的公式算出它该放在几号桶;要找的时候,用同一条公式再算一遍,直接开那个桶。这条公式就叫哈希函数,它是一张「定位公式」:不用翻,一步算出在哪。
下面是 8 个编号 0 到 7 的桶,和 6 个等着入住的名字。点一个名字,看它怎么三步进桶:先把每个字变成电脑里的编码数字并求和,再对 8 求余(因为只有 8 个桶),最后飞进算出来的那个桶。留意:全程没有「挨个对比」这个动作,位置完全是算出来的。
你可能已经发现了:阿芳和丽丽算出来都是 2 号桶!这叫哈希碰撞——桶就 8 个,名字千千万,撞桶迟早发生。怎么办?最常用的办法朴素得可爱:在桶里挂一条小链,后来的排在链上(术语叫「链地址法」)。按顺序点下面三个按钮,留意查找时翻了几次。
现在把数据量拉大,让两种找法正面赛跑。选一个数据量,点开跑。留意右边的计数器:不管左边翻到天荒地老,它永远停在 1-2 次。
🗄 翻一遍(线性查找)
翻找 0 次🗃 直达(哈希查找)
翻找 0 次哈希表可能是你每天被服务次数最多的结构——只是它总躲在幕后。下面四个场景,背后全是同一招「算出位置,一步直达」。
Set 与字典
第一课版本 B 的 Set、Python 的 dict、JS 的 Map——语言里所有「按 key 取值」的容器,肚子里都是哈希表。
缓存的键
缓存要在毫秒内回答「这个问题算过吗」,靠的就是把问题哈希成 key 直达查询——下一课的主角。
去重
训练语料去重、爬虫判断「这个网页抓过没」,都是把内容哈希后进 Set 一查——不然亿级数据两两对比要算到宇宙热寂。
session 查找
你每次打开 ChatGPT,服务器拿着 session id 在千万在线用户里瞬间找到你的会话——靠的不是翻名单。
✅ 这一课想和你分享的
- 哈希函数 = 定位公式:放和找用同一条公式,位置是算出来的,不是翻出来的
- 耗时和数据量无关:6 个人算一次,600 万人还是算一次——这就是版本 B「直达」的真相
- 碰撞不可怕:撞桶就在桶里挂条小链;链太长就加桶重排(扩容)
- 空间换时间:多备一套「定位公式 + 桶」,换来查询自由——AI 世界里 Set、字典、缓存键、去重、session 全是它
- 验收视角:看到「在大名单里挨个找」的代码,就该问一句「这里为什么不用哈希?」