当前位置: 首页 > news >正文

【C++】哈希表:简单易懂的核心讲解(含实战用法)

哈希表(Hash Table)是 C++ 中高效的键值对(key-value)存储结构,核心优势是 插入、查找、删除操作的平均时间复杂度接近 O (1)—— 比数组查找(O (n))、有序容器(如 map,O (log n))快得多,日常开发中常用来解决 “快速查找 / 去重 / 统计” 类问题。

一、先搞懂:哈希表到底是什么?(大白话版)

你可以把哈希表想象成一个 “带编号的快递柜”
  • key(键):快递的 “取件码”(唯一标识);
  • value(值):快递本身(要存储的数据);
  • 哈希函数:把 “取件码”(key)转换成 “柜子编号”(数组索引)的规则;
  • 数组 + 链表 / 红黑树:柜子的存储结构(数组是主体,链表 / 红黑树解决 “多个取件码对应同一个柜子” 的冲突问题)。
举个例子:要存储 “学生学号→学生姓名”,哈希函数可以是 “学号 mod 100”—— 学号 202501 对应柜子 1,学号 202502 对应柜子 2,直接按编号找柜子,不用逐个遍历,这就是 O (1) 效率的核心。

二、C++ 中怎么用哈希表?(重点:STL 容器)

C++ 标准库没有直接叫 “HashTable” 的类,但提供了 2 个核心哈希容器,直接用就行:
容器 特点(核心区别) 适用场景
unordered_map 存储 key-value 对,key 唯一,无序 快速查找 / 映射(如字典、缓存)
unordered_set 只存储 key,key 唯一,无序 快速去重 / 判断元素是否存在

补充:和有序容器的区别

  • map/set 是有序的(基于红黑树),查找效率 O (log n);
  • unordered_map/unordered_set 是无序的(基于哈希表),平均 O (1),但最坏 O (n)(冲突严重时),且内存占用略高。

三、实战代码:3 个最常用场景

场景 1:用 unordered_map 做 “键值映射”(如字典 / 缓存)

比如存储 “单词→释义”,快速根据单词查意思:
cpp
 
运行
 
 
 
 
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;int main() {// 1. 定义哈希表:key=string(单词),value=string(释义)unordered_map<string, string> dict;// 2. 插入元素(3种方式)dict["apple"] = "苹果";          // 直接赋值(最简洁)dict.insert({"banana", "香蕉"}); // insert 函数(键不存在时插入)dict.emplace("orange", "橙子");  // emplace(效率更高,直接构造对象)// 3. 查找元素(核心:快速查找)string key = "apple";if (dict.find(key) != dict.end()) { // find 返回迭代器,找不到返回 end()cout << key << " → " << dict[key] << endl; // 输出:apple → 苹果} else {cout << "未找到该单词" << endl;}// 4. 遍历哈希表(无序)for (auto& pair : dict) { // pair.first 是 key,pair.second 是 valuecout << pair.first << " : " << pair.second << endl;}// 5. 删除元素dict.erase("banana"); // 按 key 删除return 0;
}
 

场景 2:用 unordered_set 去重 / 判断存在

比如给一个数组去重,或快速判断某个数是否在数组中:
cpp
 
运行
 
 
 
 
#include <iostream>
#include <unordered_set>
#include <vector>
using namespace std;int main() {vector<int> nums = {1, 2, 2, 3, 3, 3, 4};unordered_set<int> unique_nums;// 去重:插入时自动忽略重复 keyfor (int num : nums) {unique_nums.insert(num); // 最终只存 1,2,3,4}// 判断元素是否存在int target = 3;if (unique_nums.count(target)) { // count 返回 0 或 1(key 唯一)cout << target << " 存在" << endl; // 输出:3 存在}// 遍历去重后的结果for (int num : unique_nums) {cout << num << " "; // 输出:1 2 3 4(顺序不确定)}return 0;
}
 

场景 3:用哈希表统计频率(如计数问题)

比如统计字符串中每个字符出现的次数:
cpp
 
运行
 
 
 
 
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;int main() {string s = "hello world";unordered_map<char, int> freq; // key=字符,value=出现次数// 统计频率for (char c : s) {freq[c]++; // 不存在的 key 会自动初始化为 0,再 ++}// 输出结果for (auto& pair : freq) {cout << "'" << pair.first << "' : " << pair.second << "次" << endl;}// 部分输出:'h':1次, 'e':1次, 'l':3次, 'o':2次...return 0;
}
 

四、关键注意点(避坑指南)

  1. key 必须可哈希:C++ 中默认支持的 key 类型:intstringdouble 等基础类型;自定义类型(如结构体)作为 key 时,需要手动重载 == 运算符(判断键是否相等)和提供哈希函数(否则编译器报错)。
  2. 无序性unordered_* 容器的遍历顺序和插入顺序无关,若需要有序,应改用 map/set
  3. 冲突问题:哈希表的效率依赖 “哈希函数的好坏”—— 好的哈希函数能减少 “多个 key 对应同一个索引” 的冲突;STL 已内置优化,日常开发不用手动处理冲突。
  4. 性能权衡:追求极致查找速度、不关心顺序 → 用 unordered_map/unordered_set;需要有序存储、允许略低效率 → 用 map/set

总结

哈希表是 C++ 中 “以空间换时间” 的典范,核心价值是 O (1) 级别的查找 / 插入 / 删除。日常开发中,只要遇到 “键值映射、去重、频率统计” 类问题,优先用 unordered_map 或 unordered_set,简单直接又高效!
http://www.jsqmd.com/news/65346/

相关文章:

  • PFLS
  • Dify 自建部署完全指南:从上手到放弃到真香
  • 工业设计必备工具:3ds Max 2025 三维建模 影视特效 下载安装教程
  • 组合计数题没做
  • 城市内涝监测架构-恒星物联解决方案
  • 院长码上办-患者投诉接办管理系统
  • 2025上海黛丽汀立体停车设备厂家实力榜:智能垂直升降技术领跑,六家高潜力本土品牌深度解析
  • 代数数论与模块格基础学习
  • 【Azure App Service】部署在应用服务上的WebJob中,为何会多出一个名为DaaS的 WebJob呢?
  • 2025上海立体车库厂家实力榜:黛丽汀以智能垂直循环技术领跑,六家高潜力本土品牌深度解析
  • spec kit 探索性问答
  • R语言保存file路径问题
  • 2025最新深圳/惠州输送线厂家TOP5推荐!深圳惠州地区组装线/装配线/生产线/输送线/老化线选购优质供应商评测
  • 【Java】面向对象基础
  • 退役入生前最后一道题
  • 归并分治模板
  • 2025燕窝品牌实力排行榜:艾玛琳商贸以溯源科技领衔,六大高潜力燕窝衍生品与礼品企业深度解析
  • ABC 435 解题报告
  • 【创作分享】一个简单易用、功能强大的 AI 图片生成工具:NanoEdit(基于Gemini 3.0 Nano Banana Pro)
  • 街头徒手健身4高阶引体向上
  • shell脚本内使用alias
  • 告别手动编码:如何用Screenshot-to-code搭建设计稿自动转HTML全流程
  • Helloworld
  • 实验4
  • ffmpeg移植到arm
  • 英语_阅读_songs playlists_待读
  • Hello,World!
  • JavaScript 转换(转译)工具———babel
  • JavaScript 转换(转译)工具———babel
  • 完整教程:特斯拉 Tesla 面试经验分享|流程全解析 + 技术细节 + 面试感受