集合与映射
复习
- 哈希函数与哈希表:根据键直接算出位置
- 拉链法与开放寻址:两种处理冲突的方式
- 抽象数据类型:先规定能做什么,再决定怎么做
TL;DR
- 集合只关心“元素在不在”,不关心顺序和重复
- 映射保存“键到值”的对应关系
- 两者都可以用哈希表或平衡树实现
- 选哪种实现,取决于是否需要有序
正文
哈希表是很强大的底层工具,但直接拿它写代码,还是太“原始”了。实际使用时,我们更常用两个建立在它之上的抽象:集合和映射。
集合:只问在不在
集合(set)关注的,是“某个元素在不在里面”。它通常支持:
- 加入一个元素
- 判断某个元素是否存在
- 删除一个元素
它有几个重要特性:元素不重复,也不关心顺序。 重复加入同一个元素,集合里仍然只有一份。
集合特别适合去重和判断存在性。比如“统计一篇文章里出现了哪些不同的单词”,用集合就再自然不过——重复出现的自然被合并。
映射:键到值的对应
映射(map,也叫字典)保存的是键到值的对应关系。它通常支持:
- 放入一对“键 → 值”
- 根据键取出对应的值
- 根据键删除
现实中的例子到处都是:电话簿里“姓名 → 号码”,配置表里“设置项 → 取值”,缓存里“请求 → 结果”。只要能想到“用一个东西查另一个东西”,背后往往就是一个映射。
映射也可以理解成“带标签的集合”:每个键唯一,但都能对应一个值。
用哪种实现
集合和映射都只是抽象,具体用什么实现,可以选:
- 哈希表:平均
O(1),但元素无序 - 平衡树:
O(log n),但能保持有序,可以按顺序遍历
这就回到了那个熟悉的判断:你需要快,还是需要有序?
- 只关心“在不在”“值是多少”,追求快:用哈希表
- 需要按键排序、范围查询、按顺序遍历:用平衡树
这也再次说明:抽象数据类型定好了“能做什么”,而选哪种实现,取决于你的具体需求。接下来的章节,我们就会走进“有序”那一派的核心结构——树。
思考题 1
集合和映射在“存什么”上有什么不同?
思考题 2
如果需要按键有序遍历,哈希表还合适吗?
小结
知识点
- 集合关注元素是否存在,不重复、不关心顺序
- 映射保存键到值的对应关系
- 两者都可用哈希表或平衡树实现
- 哈希表更快但无序,平衡树有序但稍慢
参考资料
- Wikipedia(zh):集合 (计算机科学):不重复元素的抽象容器
- Wikipedia(zh):关联数组:以键索引值的抽象数据类型
思考题答案(仅供参考)
思考题 1
集合只存“元素本身”,关心的是“在不在”;映射存的是“键到值”的对应关系,关心的是“某个键对应什么值”。可以理解为映射是给每个唯一键又附加了一个值。
思考题 2
不合适。哈希表的元素按哈希值散落,本身不维持任何顺序,无法按键有序遍历。这种需求更适合用平衡树等有序结构,它们能在 O(log n) 操作的同时保持有序。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪