- C++
unordered_map是什么
- 2025-5-1 14:53:44 @
在C++中,unordered_map
和 map
都是用于存储键值对的关联容器,但它们在多个方面存在明显区别,下面为你详细介绍:
1. 底层数据结构
map
:map
基于红黑树(一种自平衡的二叉搜索树)实现。红黑树的每个节点包含一个键值对,并且左子树节点的键小于根节点的键,右子树节点的键大于根节点的键,同时通过一些规则(如节点颜色、旋转操作等)保证树的高度平衡,从而保证插入、删除和查找操作的时间复杂度稳定。unordered_map
:unordered_map
基于哈希表实现。哈希表通过哈希函数将键映射到一个固定大小的数组(哈希桶)中,每个桶可以存储一个或多个键值对。当发生哈希冲突(即不同的键映射到同一个桶)时,通常使用链表或红黑树来处理冲突。
2. 元素顺序
map
:元素会按照键的大小进行排序,默认使用<
运算符进行比较。这意味着当你遍历map
时,元素会按照键的升序排列。例如,如果你插入键为{3, 1, 2}
的元素,遍历map
时会按照1, 2, 3
的顺序输出。unordered_map
:元素是无序的,不会按照键的任何顺序进行存储。元素的存储位置取决于哈希函数的计算结果,因此遍历unordered_map
时元素的顺序是不确定的。
3. 时间复杂度
- 插入操作:
map
:插入操作的时间复杂度为 ,因为在红黑树中插入一个节点需要进行平衡操作,以保证树的高度平衡。unordered_map
:平均情况下,插入操作的时间复杂度为 ,因为哈希表可以直接通过哈希函数计算出元素的存储位置。但在最坏情况下(如哈希冲突严重),时间复杂度可能会达到 。
- 查找操作:
map
:查找操作的时间复杂度为 ,因为需要在红黑树中进行二分查找。unordered_map
:平均情况下,查找操作的时间复杂度为 ,通过哈希函数直接定位到元素所在的桶。最坏情况下时间复杂度为 。
- 删除操作:
map
:删除操作的时间复杂度为 ,因为需要在红黑树中找到要删除的节点并进行平衡操作。unordered_map
:平均情况下,删除操作的时间复杂度为 ,但最坏情况下为 。
4. 空间复杂度
map
:由于红黑树需要额外的指针来维护节点之间的关系,因此空间复杂度相对较高,大约为 。unordered_map
:哈希表需要一个固定大小的数组(哈希桶),并且在处理哈希冲突时可能需要额外的空间(如链表或红黑树),因此空间复杂度也为 ,但通常会比map
占用更多的空间。
5. 迭代器
map
:map
的迭代器是双向迭代器,支持递增和递减操作,可以方便地遍历有序的元素。unordered_map
:unordered_map
的迭代器是前向迭代器,只支持递增操作,并且由于元素无序,迭代器的遍历顺序是不确定的。
6. 适用场景
map
:适用于需要元素按照键的顺序进行遍历的场景,例如需要对数据进行排序输出、范围查找等。此外,当对数据的有序性有要求,并且插入、删除和查找操作的时间复杂度可以接受 时,使用map
更为合适。unordered_map
:适用于对元素顺序没有要求,更注重插入、查找和删除操作的平均时间复杂度为 的场景,例如缓存系统、哈希表实现等。
示例代码
#include <iostream>
#include <map>
#include <unordered_map>
int main() {
// 使用 map
std::map<int, int> orderedMap;
orderedMap[3] = 30;
orderedMap[1] = 10;
orderedMap[2] = 20;
std::cout << "Map (ordered by key):" << std::endl;
for (const auto& pair : orderedMap) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
// 使用 unordered_map
std::unordered_map<int, int> unorderedMap;
unorderedMap[3] = 30;
unorderedMap[1] = 10;
unorderedMap[2] = 20;
std::cout << "\nUnordered map (unordered):" << std::endl;
for (const auto& pair : unorderedMap) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
return 0;
}
在上述代码中,map
会按照键的升序输出元素,而 unordered_map
的输出顺序是不确定的。
1 条评论
-
admin SU @ 2025-5-1 14:53:58
unordered_map
是C++标准模板库(STL)中的关联容器,在<unordered_map>
头文件中,位于std
命名空间 。以下是它的详细介绍:特性
- 关联性:以键值对(
pair
类型)形式存储数据 ,通过键快速检索对应的值,而非像顺序容器那样通过绝对地址访问 。例如unordered_map<string, int> umap;
,可通过字符串键找对应的整数值 。 - 无序性:内部采用哈希表存储结构 ,元素不会按键值或映射值的特定顺序排序 。区别于
map
(内部用红黑树实现,元素有序) 。 - 键唯一性:键不能重复,不存在两个键相同的元素 。
- 动态内存管理:利用内存管理模型动态分配和管理内存空间 。
工作原理
借助哈希函数,把键映射到哈希桶(数组中的位置) 。插入新键值对时,计算键的哈希值确定桶,然后将键值对存于该桶 。查找键时,同样先算哈希值定位桶,再在桶内找目标键 。因不同键可能哈希到同一桶(哈希冲突),桶内常以链表或红黑树等结构组织元素 。
常用操作
- 插入元素:可使用
insert
成员函数 ,如umap.insert({ "key", 1 });
;也能用[]
操作符,像umap["key"] = 1;
(若键不存在则插入新键值对,存在则更新值 ) 。 - 访问元素:通过
[]
操作符或at
成员函数 ,如int value = umap["key"];
,at
函数在键不存在时会抛out_of_range
异常 。 - 查找元素:用
find
成员函数 ,如auto it = umap.find("key");
,找到返回指向元素的迭代器,否则返回end()
迭代器 。 - 删除元素:可按键删除,如
umap.erase("key");
;也能按迭代器指定位置或范围删除 。 - 其他操作:
size
函数获取元素个数 ,empty
函数判断容器是否为空 ,clear
函数清空容器等 。
构造方式
- 默认构造:
std::unordered_map<key_type, value_type> umap;
- 初始化列表构造:
std::unordered_map<std::string, int> umap = { { "one", 1 }, { "two", 2 } };
- 拷贝构造:
std::unordered_map<std::string, int> umap2(umap);
(umap
为同类型容器 )
优缺点
- 优点: 平均情况下,查找、插入和删除操作时间复杂度为 ,数据量大时效率优势明显;可自定义哈希函数优化查找 。
- 缺点:哈希表构建较耗时;因哈希冲突和额外存储结构(如链表) ,空间占用可能比一些有序容器大;元素无顺序,对有序性有要求场景不适用 。
适用场景
适用于无需元素有序,更看重快速查找、插入和删除操作的场景 。如缓存系统(快速查找缓存数据 ) 、统计单词出现次数(快速插入和更新计数 ) 、实现哈希表相关功能等 。
- 关联性:以键值对(
- 1