unordered_map的理解和应用
1、介绍
unordered_map,它是一个关联容器,内部采用的是hash表结构,拥有快速检索的功能。
1.1、特性
- 关联性:通过key去检索value,而不是通过绝对地址(和顺序容器不同)
- 无序性:使用hash表存储,内部无序
- Map : 每个值对应一个键值
- 键唯一性:不存在两个元素的键一样
- 动态内存管理:使用内存管理模型来动态管理所需要的内存空间
由于unordered_map内部采用的hashtable的数据结构存储,所以,每个特定的key会通过一些特定的哈希运算映射到一个特定的位置,我们知道,hashtable是可能存在冲突的(多个key通过计算映射到同一个位置),在同一个位置的元素会按顺序链在后面。所以把这个位置称为一个bucket是十分形象的(像桶子一样,可以装多个元素)。
unordered_map内部其实是由很多哈希桶组成的,每个哈希桶中可能没有元素,也可能有多个元素。
1.2、模板
1 template < class Key, // 键值对中键的类型
2 class T, // 键值对中值的类型
3 class Hash = hash<Key>, // 容器内部存储键值对所用的哈希函数
4 class Pred = equal_to<Key>, // 判断各个键值对键相同的规则
5 class Alloc = allocator< pair<const Key,T> > // 指定分配器对象的类型
6 > class unordered_map;
主要使用的也是模板的前2个参数<键,值>
unordered_map<const Key, T> map;
参数 | 含义 |
---|---|
<key,T> | 前 2 个参数分别用于确定键值对中键和值的类型,也就是存储键值对的类型。 |
Hash = hash<Key> | 用于指明容器在存储各个键值对时要使用的哈希函数,默认使用 STL 标准库提供的 hash<key> 哈希函数。注意,默认哈希函数只适用于基本数据类型(包括 string 类型),而不适用于自定义的结构体或者类。 |
Pred = equal_to<Key> | 要知道,unordered_map 容器中存储的各个键值对的键是不能相等的,而判断是否相等的规则,就由此参数指定。默认情况下,使用 STL 标准库中提供的 equal_to<key> 规则,该规则仅支持可直接用 == 运算符做比较的数据类型。 |
1.3、unordered_map的构造函数
(1)默认构造函数:
unordered_map<int, string> mymap;
(2)使用n个元素构造unordered_map:
unordered_map<int, string> mymap = {{1, "one"}, {2, "two"}, {3, "three"}};
(3)使用给定的范围构造unordered_map:
1 vector<pair<int, string>> myVector = {{1, "one"}, {2, "two"}, {3, "three"}};
2 unordered_map<int, string> mymap(myVector.begin(), myVector.end());
(4)使用给定的哈希函数和相等比较函数构造unordered_map:
1 struct myHashFunction {
2 size_t operator()(const int& key) const {
3 return hash<int>()(key);
4 }
5 };
6
7 struct myEqualFunction {
8 bool operator()(const int& key1, const int& key2) const {
9 return key1 == key2;
10 }
11 };
12
13 unordered_map<int, string, myHashFunction, myEqualFunction> mymap;
2、unordered_map的函数应用
成员方法 | 功能 |
---|---|
begin() | 返回指向容器中第一个键值对的正向迭代器。 |
end() | 返回指向容器中最后一个键值对之后位置的正向迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。 |
empty() | 若容器为空,则返回 true;否则 false。 |
size() | 返回当前容器中存有键值对的个数。 |
2.1、unordered_map迭代器的示例:
(1)使用迭代器遍历unordered_map,从begin()到end()。在循环中,使用it->first和it->second分别访问键和值。
1 #include <iostream> 2 #include <unordered_map> 3 int main() { 4 std::unordered_map<int, std::string> mymap = {{1, "one"}, {2, "two"}, {3, "three"}}; 5 // 使用迭代器遍历unordered_map 6 for (auto it = mymap.begin(); it != mymap.end(); ++it) { 7 std::cout << "Key: " << it->first << ", Value: " << it->second << std::endl; 8 } 9 return 0; 10 } 11 //Key: 1, Value: one 12 //Key: 2, Value: two 13 //Key: 3, Value: three
(2)使用范围for循环遍历unordered_map,这种方式更加简洁。使用const auto& pair来捕获每个键值对,并使用pair.first和pair.second分别访问键和值。
1 #include <iostream> 2 #include <unordered_map> 3 int main() { 4 std::unordered_map<int, std::string> mymap = {{1, "one"}, {2, "two"}, {3, "three"}}; 5 // 使用范围for循环遍历unordered_map 6 for (const auto& pair : mymap) { 7 std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl; 8 } 9 return 0; 10 } 11 //Key: 1, Value: one 12 //Key: 2, Value: two 13 //Key: 3, Value: three
2.2、unordered_map的容量和访问函数
max_size() | 返回容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同。 |
operator[key] | 该模板类中重载了 [] 运算符,其功能是可以向访问数组中元素那样,只要给定某个键值对的键 key,就可以获取该键对应的值。注意,如果当前容器中没有以 key 为键的键值对,则其会使用该键向当前容器中插入一个新键值对。 |
at(key) | 返回容器中存储的键 key 对应的值,如果 key 不存在,则会抛出 out_of_range 异常。 |
find(key) | 查找以 key 为键的键值对,如果找到,则返回一个指向该键值对的正向迭代器;反之,则返回一个指向容器中最后一个键值对之后位置的迭代器(如果 end() 方法返回的迭代器)。 |
count(key) | 在容器中查找以 key 键的键值对的个数。 |
(1)empty() 函数用于检查 unordered_map 是否为空,即是否不包含任何键值对。如果 unordered_map 为空,则返回 true;否则返回 false。
1 #include <iostream>
2 #include <unordered_map>
3 int main() {
4 std::unordered_map<int, std::string> myMap;
5
6 if (myMap.empty()) {
7 std::cout << "myMap is empty" << std::endl;
8 } else {
9 std::cout << "myMap is not empty" << std::endl;
10 }
11
12 myMap = {{1, "one"}, {2, "two"}, {3, "three"}};
13
14 if (myMap.empty()) {
15 std::cout << "myMap is empty" << std::endl;
16 } else {
17 std::cout << "myMap is not empty" << std::endl;
18 }
19
20 return 0;
21 }
22 //myMap is empty
23 //myMap is not empty
(2)size() 函数返回 unordered_map 中存储的键值对的数量。
1 #include <iostream>
2 #include <unordered_map>
3
4 int main() {
5 std::unordered_map<int, std::string> myMap = {{1, "one"}, {2, "two"}, {3, "three"}};
6
7 std::cout << "Size of myMap: " << myMap.size() << std::endl;
8
9 return 0;
10 }
11 //Size of myMap: 3
(3)operator[] 用于访问或修改指定键的值。如果键不存在,则会插入一个新的键值对,其中键为指定的键,值为该类型的默认值。
1 #include <iostream>
2 #include <unordered_map>
3
4 int main() {
5 std::unordered_map<std::string, int> my_map;
6
7 // 使用operator[]插入键值对
8 my_map["apple"] = 1;
9 my_map["banana"] = 2;
10
11 // 使用operator[]访问键值对
12 std::cout << "Apple: " << my_map["apple"] << std::endl;
13 std::cout << "Banana: " << my_map["banana"] << std::endl;
14
15 // 如果键不存在,operator[]将插入新的键值对,并赋予默认值
16 std::cout << "Orange: " << my_map["orange"] << std::endl;
17
18 return 0;
19 }
20 //Apple: 1
21 //Banana: 2
22 //Orange: 0
(4)find方法用于查找具有指定键的元素
1 std::unordered_map<Key, Value> my_map;
2 // 插入一些元素...
3
4 // 使用find方法查找具有指定键的元素
5 auto it = my_map.find("key");
6
7 if (it != my_map.end()) {
8 // 键存在于unordered_map中
9 std::cout << "Found key: " << it->first << ", value: " << it->second << std::endl;
10 } else {
11 // 键不存在于unordered_map中
12 std::cout << "Key not found" << std::endl;
13 }
(5)count方法用于获取具有指定键的元素的数量
1 std::unordered_map<Key, Value> my_map;
2 // 插入一些元素...
3
4 // 使用count方法获取具有指定键的元素数量
5 size_t count = my_map.count("key");
6
7 if (count > 0) {
8 std::cout << "Key found" << std::endl;
9 } else {
10 std::cout << "Key not found" << std::endl;
11 }
(6)insert方法用于插入元素
1 std::unordered_map<Key, Value> my_map;
2
3 // 使用insert方法插入元素
4 std::pair<std::unordered_map<Key, Value>::iterator, bool> result = my_map.insert({"key", "value"});
5
6 if (result.second) {
7 // 插入成功
8 std::cout << "Inserted key: " << result.first->first << ", value: " << result.first->second << std::endl;
9 } else {
10 // 插入失败(键已存在)
11 std::cout << "Key already exists" << std::endl;
12 }
13
14 //Inserted key: key, value: value
(7)erase方法用于删除元素
1 std::unordered_map<Key, Value> my_map;
2 // 插入一些元素...
3
4 // 使用erase方法删除具有指定键的元素
5 auto it = my_map.find("key");
6 if (it != my_map.end()) {
7 my_map.erase(it);
8 std::cout << "Erased key: " << it->first << std::endl;
9 } else {
10 std::cout << "Key not found" << std::endl;
11 }
12
13 //Erased key: key
(8)clear方法用于删除所有元素
1 std::unordered_map<Key, Value> my_map;
2 // 插入一些元素...
3
4 // 使用clear方法删除所有元素
5 my_map.clear();
6
7 if (my_map.empty()) {
8 std::cout << "Map is empty" << std::endl;
9 } else {
10 std::cout << "Map is not empty" << std::endl;
11 }
12
13 //Map is empty
(9)swap方法用于交换两个unordered_map对象的内容
1 std::unordered_map<Key, Value> my_map1;
2 // 插入一些元素到my_map1...
3
4 std::unordered_map<Key, Value> my_map2;
5 // 插入一些元素到my_map2...
6
7 // 使用swap方法交换my_map1和my_map2的内容
8 my_map1.swap(my_map2);
9
10 // 现在my_map1包含my_map2以前的元素,反之亦然
(10)其他
1 #include <iostream>
2 #include <string>
3 #include <unordered_map>
4 using namespace std;
5 int main()
6 {
7 //创建空 umap 容器
8 unordered_map<string, string> umap;
9 //向 umap 容器添加新键值对
10 umap.emplace("Python教程", "http://c.biancheng.net/python/");
11 umap.emplace("Java教程", "http://c.biancheng.net/java/");
12 umap.emplace("Linux教程", "http://c.biancheng.net/linux/");
13 //输出 umap 存储键值对的数量
14 cout << "umap size = " << umap.size() << endl;
15 //使用迭代器输出 umap 容器存储的所有键值对
16 for (auto iter = umap.begin(); iter != umap.end(); ++iter) {
17 cout << iter->first << " " << iter->second << endl;
18 }
19 return 0;
20 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了