GESP7级C++考试语法知识(四、哈希表(3、哈希冲突)
第三课:《撞车事故现场——哈希冲突》
一、国王的邮箱系统出事故了!
1、上一课里,我们认识了哈希函数。
(1)智慧大臣发明了:
🏆 魔法编号机
规则:
hash = x % 10;(2)例如:
18 → 8号邮箱 25 → 5号邮箱 42 → 2号邮箱(3)大家都顺利找到了自己的邮箱。
国王高兴极了:
“这真是世界上最伟大的发明!”
2、可是第二天早上。
邮局管理员慌慌张张跑进皇宫。
大喊:
“不好了!不好了!”
“邮箱撞车了!”
二、什么叫撞车?
1、管理员拿出记录本。
居民:
18计算:
18 % 10得到:
8进入:
8号邮箱2、又来了一个居民:
28计算:
28 % 10得到:
8竟然也是:
8号邮箱3、第三位居民:
38计算:
38 % 10结果还是:
8号邮箱4、现在情况变成:
8号邮箱 ├── 18 ├── 28 └── 385、国王傻眼了:
“怎么回事?”
“为什么三个居民抢同一个邮箱?”
三、哈希冲突出现了
这种现象有个专业名字:
哈希冲突(Hash Collision)
1、定义非常简单:
两个不同的数据 经过哈希函数计算 得到同一个位置就叫:
哈希冲突2、例如:
18 → 8 28 → 8 38 → 8虽然:
18 ≠ 28 ≠ 38但是:
hash(18) = hash(28) = hash(38)3、这就是:
💥 哈希冲突
四、为什么一定会冲突?
1、有的同学会问:
“汉克老师,能不能设计一个永远不冲突的哈希函数?”
答案:
❌ 基本不可能。
2、我们来看看。
邮箱数量:
10个居民数量:
100个3、请问:
100个人 放进 10个邮箱会发生什么?
肯定有邮箱里不止一个人。
例如:
邮箱1 住10个人 邮箱2 住8个人 邮箱3 住12个人这就像:
100只小兔子 塞进10个笼子总会有笼子里挤着好几只兔子。
4、这就是数学里的:
鸽巢原理
(又叫抽屉原理)
5、简单说:
东西比位置多 冲突必然发生五、哈希表管理员怎么办?
国王问:
“邮箱撞车了怎么办?”
智慧大臣笑了:
“没关系。”
“我们早就准备好了办法。”
于是。
哈希王国发明了两种解决方案。
第一种方案:拉链法
六、拉链法登场
(1)假设:
18 → 8 28 → 8 38 → 8都进入:
8号邮箱(2)那怎么办?
大臣说:
“不要赶走他们。”
“让他们排队。”
于是:
8号邮箱 18 ↓ 28 ↓ 38变成:
8号邮箱 | |--18 | |--28 | |--38(3)就像:
🏠 一个宿舍
里面住了:
18 28 38三个人。
(4)这种方法叫:
拉链法(Chain)
(5)为什么叫拉链法?
因为像衣服拉链一样:
一个接一个连起来。
七、查找过程
1、现在找:
282、先算:
28 % 10得到:
8号邮箱3、进入8号邮箱:
18 28 384、依次检查:
18 不是 28 找到成功!
八、拉链法的优点
1、优点:
✅ 简单
✅ 好理解
✅ 实际应用广泛
2、C++很多哈希表实现都用了类似思想。
第二种方案:开放寻址法
九、停车场故事
1、智慧大臣又发明另一种办法。
(1)假设:
18进入:
8号邮箱(2)现在:
28也想进入:
8号邮箱(3)结果发现:
8号邮箱满了怎么办?
2、大臣说:
“向后找空位!”
(1)例如:
邮箱编号 0 1 2 3 4 5 6 7 8 ←18 9 ←空(2)于是:
28放到:
9号邮箱(3)再来:
38计算:
8号邮箱发现:
8满了 9满了继续找。
找到:
0号邮箱于是:
38放进去。
(4)结果:
0 ←38 8 ←18 9 ←283、这种方法叫:
开放寻址法
(Open Addressing)
意思就是:
原来的位置满了 继续找空位置十、生活中的理解
1、拉链法像什么?
电影院。
第8排坐满了。
于是:
18 28 38都坐在同一排。
2、开放寻址法像什么?
停车场。
车位8满了。
那就:
停9 停0 停1 ……一直找空车位。
十一、为什么冲突越少越好?
1、假设:
8号邮箱 18 28 38 48 58 68 78 88 982、现在找:
98必须看:
18 28 38 48 58 68 78 88 98才能找到。
3、原本:
O(1)的查找。
慢慢变成:
O(n)了。
4、所以优秀哈希函数的目标是:
让数据尽量均匀分散不要全挤在一起。
十二、现实中的哈希表
1、实际C++中的:
unordered_map内部已经帮我们做好了:
✅ 哈希函数
✅ 冲突处理
✅ 自动扩容
2、例如:
unordered_map<int,int> mp; mp[18] = 1; mp[28] = 2; mp[38] = 3;即使发生冲突。
程序员也不用管。
系统自动处理。
十三、小试牛刀
规则:
hash = x % 10;计算下面数字会进入哪个邮箱?
第一题
15计算:
15 % 10 = 5答案:
5号邮箱第二题
25计算:
25 % 10 = 5答案:
5号邮箱发生了什么?
答案:
💥 哈希冲突
第三题
35计算:
35 % 10 = 5答案:
5号邮箱结果:
5号邮箱 15 25 35又发生冲突了。
本课总结
1、今天我们认识了哈希表最大的敌人:
💥 哈希冲突(Hash Collision)
2、什么是冲突?
不同数据 得到相同邮箱例如:
18 → 8 28 → 8 38 → 83、为什么会冲突?
数据太多 邮箱太少根据抽屉原理:
冲突不可避免4、解决办法:
方法1:拉链法
8号邮箱 18 ↓ 28 ↓ 38方法2:开放寻址法
8号邮箱满了 去9号 9号满了 去0号5、魔法口诀
哈希表,很神奇, 快速查找效率高。 不同数据同位置, 这就叫做哈希冲突。 拉链法,排队站; 开放寻址找空房。 冲突越少越优秀, 查找速度才够强!下一课,我们将正式进入 C++ 的真实哈希表世界:
《藏宝图仓库——认识 unordered_map》
届时同学们将第一次使用真正的:
unordered_map<string,int>实现姓名→分数、学号→学生等超级实用的哈希表应用!🚀
