1. 简述
std::map、std::multimap 和 std::unordered_map 是 C++ 标准模板库(STL)中的三种关联容器,它们提供了存储键值对(pair)的方式,并允许通过键来快速检索值。这三者之间的主要区别在于它们的内部数据结构和对元素的排序方式。
2. std::map的特点
有序性:std::map 中的元素按照键的顺序存储,因此可以高效地进行中序遍历。
唯一性:每个键在 std::map 中都是唯一的,不允许重复的键存在。
性能:std::map 提供了对元素的高效查找、插入和删除操作,时间复杂度通常为 O(log n)。
内存消耗:由于使用平衡二叉搜索树,std::map 相比于 std::unordered_map 可能会有更高的内存消耗。
可预测性:由于元素的有序性,std::map 在迭代时提供了可预测的顺序,这在某些算法中非常有用。
3. std::map构造及其用法
(1)构造map
首先需要引用头文件:#include <map>
默认构造:
std::map<int, std::string> amap;
使用初始化列表进行构造:
std::map<int, std::string> myMap = {
{1, "one"},
{2, "two"},
{3, "three"}
};
复制构造:
std::map<int, std::string> myMap1 = { {1, "one"}, {2, "two"} };
std::map<int, std::string> myMap2(myMap1);
(2)插入
构造std::pair并插入:
amap.insert(std::pair<int, std::string>(5, “Derek”));
使用make_pair(无需专门指定类型):
amap.insert(std::make_pair(5, “Derek”));
使用amap的value_type构造插入:
amap.insert(std::map<int, std::string>::value_type(5, “Derek”));
使用数组方式插入(注意,这种方式会覆盖原有已经存在的键值对):
amap.insert[1] = “Eaton”;
(3)删除元素
it = myMap.erase(it); // 删除迭代器指向的元素
当使用迭代器删除元素以后,需要更新迭代器(原迭代器已经失效)。
myMap.erase(myMap.begin(), myMap.end()); // 删除所有元素
(4)查找元素
std::map的元素查找可以使用find。
auto it = myMap.find(3);
if (it != myMap.end()) {
// 找到元素
}
(5)访问元素
可以使用下标或at访问元素。
std::string name = amap[2];
或
std::string name = amap.at(2);
值得注意的是,使用at进行元素的访问过程中,如果元素不存在,则会报出std::out_of_range异常。
(6)获取大小
amap.size();
4. std::map例程
#include <iostream>#include <map>int main(int argc, char* argv[]){/** 创建一个 std::map. */std::map<int, std::string> myMap;/** 插入键值对. */myMap.insert({1, "One"});myMap.insert({2, "Two"});myMap.insert({3, "Three"});/** 遍历 std::map. */for (const auto& pair : myMap) {std::cout << pair.first << ": " << pair.second << std::endl;}/** 访问元素. */std::cout << "The value for key 2 is: " << myMap[2] << std::endl;return 0;}
5. std::multimap
std::multimap 是 C++ 标准模板库中的一个关联容器,它类似于 std::map,但允许每个键关联多个值。std::multimap 基于平衡二叉搜索树实现,因此它保持了元素的有序性,按照键的顺序组织元素。
6. std::multimap的特点
键的多重性:与 std::map 不同,std::multimap 允许一个键对应多个值。
有序性:std::multimap 中的元素按照键的顺序存储,因此可以高效地进行中序遍历。
性能:std::multimap 提供了对元素的高效查找、插入和删除操作,时间复杂度通常为 O(log n)。
内存消耗:由于使用平衡二叉搜索树,std::multimap 相比于 std::unordered_multimap 可能会有更高的内存消耗。
7. std::multimap例程
#include <iostream>#include <multimap>int main(int argc, char* argv[]){/** 创建一个 std::multimap. */std::multimap<int, std::string> myMultiMap;// 插入具有相同键的多个元素myMultiMap.insert({1, "One"});myMultiMap.insert({1, "Uno"});myMultiMap.insert({2, "Two"});myMultiMap.insert({3, "Three"});/** 遍历 std::multimap. */for (const auto& pair : myMultiMap) {std::cout << pair.first << ": " << pair.second << std::endl;}/** 查找具有特定键的所有元素. */auto range = myMultiMap.equal_range(1);std::cout << "Values for key 1: ";for (auto it = range.first; it != range.second; ++it) {std::cout << it->second << " ";}std::cout << std::endl;/** 访问特定键的第一个值. */std::string firstValue;auto it = myMultiMap.find(2);if (it != myMultiMap.end()) {firstValue = it->second;}std::cout << "The first value for key 2 is: " << firstValue << std::endl;/** 删除特定键的所有元素. */myMultiMap.erase(3);/** 再次遍历 std::multimap 确认元素已被删除. */std::cout << "Multimap after erasing key 3:" << std::endl;for (const auto& pair : myMultiMap) {std::cout << pair.first << ": " << pair.second << std::endl;}return 0;}
8. unordered_map
std::unordered_map 是一个基于哈希表的容器,它提供了最快的平均时间复杂度(通常是 O(1))来访问元素。与 std::map 和 std::multimap 不同,std::unordered_map 中的元素没有特定的顺序,元素的顺序取决于哈希函数和哈希表的内部结构。
9. std::unordered_map特点
无序性:std::unordered_map 中的元素不是按照键的顺序存储的,而是根据键的哈希值。
快速访问:由于使用了哈希表,std::unordered_map 通常能够提供接近常数时间复杂度(O(1))的查找、插入和删除操作。
内存消耗:相比于 std::map,std::unordered_map 可能会有更多的内存消耗,因为哈希表需要额外的空间来存储桶(buckets)和哈希值。
键的唯一性:std::unordered_map 中的键是唯一的,不允许有重复的键存在。
10. std::unordered_map例程
#include <iostream>#include <unordered_map>int main(int argc, char*argv[]){/** 创建一个 std::unordered_map. */std::unordered_map<int, std::string> myUnorderedMap;/** 插入键值对. */myUnorderedMap.insert({1, "One"});myUnorderedMap.insert({2, "Two"});myUnorderedMap.insert({3, "Three"});/** 遍历 std::unordered_map. */for (const auto& pair : myUnorderedMap) {std::cout << pair.first << ": " << pair.second << std::endl;}/** 访问特定键的值. */std::string value = myUnorderedMap.at(2); ///< 抛出异常,如果键不存在/** 或者使用下标操作符,它返回一个默认值如果键不存在. */std::string value2 = myUnorderedMap[2];/** 查找元素. */auto it = myUnorderedMap.find(3);if (it != myUnorderedMap.end()) {std::cout << "The value for key 3 is: " << it->second << std::endl;}/** 删除元素. */myUnorderedMap.erase(it); ///< 删除迭代器指向的元素myUnorderedMap.erase(1); ///< 删除特定键的所有元素/** 再次遍历 std::unordered_map 确认元素已被删除. */std::cout << "Unordered map after erasing keys 1 and 3:" << std::endl;for (const auto& pair : myUnorderedMap) {std::cout << pair.first << ": " << pair.second << std::endl;}return 0;}