新闻中心
c++如何实现一个哈希表_c++数据结构unordered_map原理【源码】

哈希表在 C++ 中最常用的实现就是 std::unordered_map,它底层基于开放寻址或链地址法(主流实现是**分离链表法**),提供平均 O(1) 的插入、查找和删除。它不是标准强制规定实现方式,但所有主流 STL(如 libstdc++、libc++、MSVC STL)都采用**哈希 + 拉链(bucket + linked list)**结构,配合动态扩容和负载因子控制。
核心结构:桶数组 + 单向链表节点
每个桶(bucket)是一个指针,指向一条以哈希值相同元素构成的单向链表。关键成员通常包括:
-
b
ucket 数组(vector) :大小为质数(避免哈希冲突聚集),初始一般为 11 或 17 -
Node 结构:含
key、value、next指针(可能还有 hash 值缓存) -
元素总数(size)和桶数量(bucket_count):用于计算负载因子
load_factor = size / bucket_count - 最大负载因子(max_load_factor):默认 1.0,超限触发 rehash
哈希与映射:如何定位 bucket
给定 key,流程如下:
- 调用
std::hash<key>()(key)</key>得到一个 size_t 类型哈希值(对自定义类型需特化或传 Hash 函数对象) - 用
hash_value % bucket_count算出下标(libstdc++ 实际用更优的hash_value & (bucket_count - 1),但前提是 bucket_count 是 2 的幂;而实际它用的是质数,所以仍是取模) - 遍历该 bucket 对应链表,用
operator==比较 key(注意:哈希相等 ≠ key 相等,必须二次判断)
插入与扩容:rehash 是性能关键
插入逻辑简述:
Songtell
Songtell是第一个人工智能生成的歌曲含义库
164
查看详情
- 计算 bucket 下标
- 遍历链表检查 key 是否已存在(存在则更新 value)
- 不存在则 new Node 插入链表头(或尾,取决于实现),size++
- 若
size > max_load_factor * bucket_count,触发 rehash:分配新桶数组(更大质数),把所有旧节点重新 hash 插入新表
libstdc++ 中 rehash 会将 bucket_count 设为「不小于指定值的最小质数」,质数表是静态预置的(如 11, 23, 47, 97...)。
简易手写版(简化链地址法)示意
(仅演示核心逻辑,无异常/allocator/迭代器等完整功能)template <typename K, typename V, typename Hash = std::hash<K>, typename Eq = std::equal_to<K>>
class simple_unordered_map {
struct Node { K key; V value; Node* next; Node(const K& k, const V& v) : key(k), value(v), next(nullptr) {} };
std::vector<Node*> buckets;
size_t _size = 0;
float max_load = 1.0f;
Hash hasher;
Eq equal;
<pre class="brush:php;toolbar:false;">size_t hash_index(const K& k) const { return hasher(k) % buckets.size(); }
void rehash(size_t new_bucket_count) {
std::vector<Node*> new_buckets(new_bucket_count, nullptr);
for (Node* node : buckets) {
while (node) {
Node* next = node->next;
size_t idx = hasher(node->key) % new_bucket_count;
node->next = new_buckets[idx];
new_buckets[idx] = node;
node = next;
}
}
buckets.swap(new_buckets);
}
public: simple_unordered_map() { buckets.resize(11, nullptr); }
V& operator[](const K& k) {
size_t idx = hash_index(k);
Node*& head = buckets[idx];
for (Node* p = head; p; p = p->next) {
if (equal(p->key, k)) return p->value;
}
// 未找到,插入新节点(头插)
Node* newNode = new Node(k, V{});
newNode->next = head;
buckets[idx] = newNode;
++_size;
if (_size > max_load * buckets.size()) rehash(/*下一个质数*/);
return buckets[idx]->value;
}
~simple_unordered_map() {
for (Node* head : buckets) {
while (head) {
Node* next = head->next;
delete head;
head = next;
}
}
}};
基本上就这些。真正工业级实现(如 GCC 的 libstdc++/include/bits/hashtable.h)还涉及内存池、移动语义、迭代器失效规则、const_iterator 支持、emplace 优化等,但骨架一致:哈希分桶 + 链表容错 + 动态扩容。理解这个模型,读源码就不容易迷失在模板嵌套里。
以上就是c++++如何实现一个哈希表_c++数据结构unordered_map原理【源码】的详细内容,更多请关注其它相关文章!
# 迭代
# 闵行网站建设思创
# 巫山知名网站建设企业
# 简单网站建设的过程
# 山东正规seo优化课程
# 网站怎么建设用户体验
# 网站优化设备公司推荐
# 网站建设后期成本怎么算
# 竞品关键词排名怎么查
# 长葛营销推广公司怎么样
# 东阿外贸网站建设
# 与其他
# node
# 特化
# 是一个
# 的是
# 如何使用
# 遍历
# 如何实现
# 数据结构
# 链表
# red
# 质数
# c++
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
如何使用spryker/configurable-bundles-products-resource-relationship模块解决复杂产品捆绑关系难题
Python大型XML文件高效流式解析教程
抖音未来赚钱的新趋势 2025年值得关注的变现风口分析
消息称三星明年 2 月正式发布 HBM4,与 SK 海力士同台竞技
抖音创作助手登录入口_抖音创作辅助工具官网直达
网易大神账号申诉需要多久_网易大神账号申诉流程说明
C#如何安全地从用户上传的XML文件中读取数据? 验证与清理策略
c++如何使用chrono库处理时间_c++标准库时间与日期操作
Win10双系统截图高效法 截屏快捷键速记【技巧】
怎么去除衣服上的口红印_生活小妙招教你用酒精轻松擦除
J*a里如何使用forEach遍历Map_Map遍历方法说明
将HTML动态表格多行数据保存到Google Sheet的教程
解决Rails应用中内容错位与Turbo警告:meta标签误用导致富文本渲染异常
虫虫漫画精品漫画官网_虫虫漫画精品漫画官网进入精品漫画
Win10桌面图标出现小盾牌怎么办 Win10去除UAC图标教程【解决】
J*aScript map 迭代中检测空数组元素的有效方法
C++如何连接MySQL数据库_C++使用Connector/C++操作MySQL数据库教程
抓大鹅解压小游戏 抓大鹅摸鱼解压入口
零跑汽车11月交付量达70327台 实现连续9个月正增长
css子元素高度不一致导致布局错位怎么办_使用align-items:stretch解决高度差异
深入理解与实现最大堆的Heapify过程:常见错误与修正
Lar*el Form Request中唯一性验证在更新操作中的正确实现
J*a 递归快速排序中静态变量的状态管理与陷阱
Yandex免登录官网入口_俄罗斯Yandex搜索引擎直达链接
海量存储:机器视觉智能化的核心基石
J*aScript中在Map循环中检测并处理空数组元素
高德地图总提示网络异常怎么办 高德地图离线导航设置与网络排查方法
铁路12306改签能改到更早的车次吗_铁路12306改签提前车次规则
痛风发作了怎么办? 快速止痛和后期饮食调理
J*a里如何实现线程安全的懒加载单例_懒加载单例实现方法解析
Win10系统服务哪些可以禁用 Win10安全优化服务列表【干货】
wps文字怎么插入目录并自动更新_wps文字如何插入目录并自动更新方法
XML中包含HTML标签导致解析错误? 正确嵌入非XML数据的两种方法
照顾宝贝2小游戏点击立即在线玩
铁路12306的积分有效期是多久_铁路12306积分有效期说明
j*a toString()的覆盖
Word2013如何插入视频和音频媒体_Word2013媒体插入的多媒体支持
Flexbox布局实践:实现粘性导航栏与底部固定页脚
Win11怎么开启高性能模式_Windows 11电源计划优化设置
J*aScript异步迭代器_j*ascript异步遍历
Golang如何使用context实现超时取消_Golang context超时取消模式实践
在FastAPI中利用lifespan与依赖注入高效管理Redis连接池
Composer如何在生产环境安全地执行composer update
蛙漫2日版入口 WAMAN2(日版)无删减漫画官网链接
荣耀Play7TPro怎样在信息App置顶客服对话_iPhone荣耀Play7TPro信息App置顶客服对话【优先查看】
b站赚钱渠道_b站收益来源
qq游戏网页版直接玩_qq游戏免下载快速入口
Lar*el 递归关系中排除指定分支的教程
JUnit5/Mockito:优雅测试内部依赖与异常处理的实践
Android Studio计算器C键逻辑错误排查与修复:条件判断优化指南


2025-12-09
浏览次数:次
返回列表
ucket 数组(vector