【C++】 map/multimap底层原理与逻辑详解

【C++】 map/multimap底层原理与逻辑详解
- 摘要
- 目录
- 一、`map`
- 1. 类模板认识
- 2. 构造函数认识
- 3. 迭代器和范围for的使用
- 4. insert的使用
- 5. empty 和size的使用
- 6. erase的使用
- 7. swap 和 clear的使用
- 8. find的使用
- 9. count的使用
- 11. lower_bound 和 upper_bound的使用
- 12. equal_range的使用
- 13. operator= 的使用
- 14. operator[ ] 的使用
- 二、`multimap`
- 1. 模板和类模板的认识
- 2. insert的使用
- 3. erase的使用
- 4. find的使用
- 5. count的使用
- 6. equal_range的使用
- 总结
摘要
本文系统介绍了C++ STL中的两种关键关联容器:map和multimap。map存储唯一的键值对,提供快速的查找、插入和删除操作,时间复杂度为O(log n)。其核心特性包括自动排序、支持operator[]进行直接访问和修改,以及丰富的迭代器操作。文章详细讲解了map的构造函数、元素插入(insert)、删除(erase)、查找(find, count)、范围操作(lower_bound, upper_bound, equal_range)等关键方法的使用。
multimap作为map的扩展,允许键的重复,适用于需要存储多个相同键对应不同值的场景。与map的主要区别在于:不支持operator[](因为无法确定返回哪个值)、insert允许插入重复键、erase删除所有匹配键的元素、find返回第一个匹配元素、count返回实际重复数量,以及equal_range在处理重复键时特别有用。两者都基于红黑树实现,保证了元素的有序性,是处理键值对数据的强大工具。
键对值技巧详解<----------请点击
目录
一、map
1. 类模板认识

- 定义了一个名为
map的类模板,它是 C++ 标准库中的一个关联容器,用于存储键值对(key-value pairs)。在 C++ 中,类模板是一种泛型编程的机制,允许我们在定义类时使用类型参数,类型将在实际使用时决定。通过这种方式,map类模板可以在不同的应用场景下被灵活使用。map类模板有四个类型参数,分别是Key、T、Compare和Alloc。其中,Key代表存储的键的类型,T代表存储的值的类型。键值对中的键是唯一的,且map会根据键的大小进行自动排序。默认情况下,键是按升序排列的,排序的规则由Compare来决定。Compare的默认值是less<Key>,即按升序排列。如果我们希望自定义排序规则,可以传入其他比较器。Alloc是分配器类型,用来指定map在存储元素时如何分配内存,默认值是allocator<pair<const Key, T>>,即标准的内存分配器。这个默认值对于大多数使用场景来说是足够的,但如果需要特殊的内存管理方式,可以自定义分配器。
类模板的这种设计方式使得map能够非常灵活地处理不同的数据类型。例如,如果你定义了一个map<int, string>,那么它将存储int类型的键和string类型的值。你可以根据需要使用不同的键值对类型。由于map是一个模板类,它能够在编译时根据你提供的类型生成适用于该类型的代码,因此我们可以避免为每种类型编写重复的代码。- 在实际使用中,
map容器在大多数情况下会使用默认的比较器和分配器,但如果我们有特定需求,可以像这样提供自定义参数。例如,map<int, string, greater<int>>会使得map按降序排序,而不是默认的升序排序。通过这样的方式,map可以适应各种不同的场景,提供灵活的键值对存储解决方案。
2. 构造函数认识

第一段是 empty 函数:
explicit map (const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());
这个构造函数定义了
map对象的初始化方式。首先,explicit关键字意味着这个构造函数不能用于隐式转换和复制初始化。换句话说,只有显式地调用该构造函数时,才能构造一个map对象。构造函数接收两个参数,key_compare和allocator_type,它们分别用于设置map中键的比较方式和内存分配方式。key_compare是一个比较器,用来决定map中键的排序规则,默认使用key_compare(),通常是less<Key>,即升序排序。allocator_type是分配器类型,决定了map如何分配内存,默认使用allocator_type(),通常是allocator<pair<const Key, T>>,即标准内存分配器。这两个参数都是可选的,意味着如果不提供这两个参数,map会使用默认的比较器和内存分配器。
第二段是一个范围构造函数:
template <class InputIterator>map (InputIterator first, InputIterator last, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());
这个构造函数允许你从一个输入范围(由迭代器
first和last定义)初始化map。即你可以通过一对迭代器将一个序列(如vector、list等)中的元素复制到新的map中。InputIterator是一个模板参数,表示输入范围的迭代器类型。first和last是两个迭代器,定义了一个范围,map会将该范围中的元素插入到自己内部。和第一个构造函数一样,key_compare和allocator_type也是可选的,用于指定排序规则和内存分配方式。如果没有提供这些参数,map会使用默认的比较器和分配器。
第三段是复制构造函数:
map (const map& x);
这是
map的复制构造函数,它用于通过另一个已经存在的map对象x来构造一个新的map。复制构造函数会将x中的所有元素复制到新构造的map中,包括键值对、排序规则、内存分配器等。复制构造函数在我们需要创建一个新map,而且需要复制已有map中的内容时非常有用。与前两个构造函数不同,这个构造函数不接受排序规则或分配器参数,因为它会复制源map的排序规则和分配器。这个构造函数确保新创建的map会和源map在元素和行为上完全相同。
#include<iostream>
#include<map>
#include<utility>
using namespace std;int main()
{pair<string, string> arr[] = { make_pair("delete", "删除"),make_pair("insert", "插入") ,make_pair("add", "增加") };map<string, string> m1;map<string, string> m2(arr, arr + sizeof(arr) / sizeof(arr[0]));map<string, string> m3(m2);return 0;
}
3. 迭代器和范围for的使用
map容器中的元素是pair类型的结构对象,而不像其他容器(如vector或list)那样直接存储数据。在map中,每个元素都包含两个部分:键(key)和值(value),它们被存储在一个pair<const Key, T>结构中。因此,
map的迭代器和其他容器的迭代器有所不同。虽然迭代器仍然遵循基本的框架,但我们获取的元素是一个pair对象,而不是单一的值。
- 在
map中,迭代器解引用后得到的是一个pair结构。我们可以通过该结构访问其中的first和second,即key和value。这两者分别存储在pair的first和second成员中。- 由于
map的迭代器实际上是指向pair结构的指针,因此可以通过->运算符来访问pair的成员变量。使用箭头运算符比直接解引用并访问成员要简洁得多。实际上,map的迭代器已经重载了箭头->运算符,使得它能够直接访问pair结构的成员。- 由于
map容器存储的是结构体pair,而且迭代器返回的是一个指向该结构体的指针,因此我们可以通过范围for来遍历map,并且直接访问pair中的成员。为了避免不必要的拷贝,建议使用常量引用
const auto&来进行遍历。这样可以避免复制pair对象的开销,同时确保值不会被修改。
for (const auto& e : map) {cout << e.first << ", " << e.second << endl;
}
const auto& e表示我们通过常量引用e获取每个pair对象,而不会产生额外的拷贝。e.first访问pair中的键,e.second访问pair中的值。这种方式不仅节省了内存,还保证了代码的简洁性和可读性。
#include<iostream>
#include<map>
#include<utility>
using namespace std;int main()
{pair<string, string> arr[] = { make_pair("delete", "删除"),make_pair("insert", "插入") ,make_pair("add", "增加") };map<string, string> m2(arr, arr + sizeof(arr) / sizeof(arr[0]));auto it = m2.begin();//map<string, string>::iterator it = m2.begin();while (it != m2.end()){cout << (*it).first << ':' << (*it).second << endl;cout << it->first << ':' << it->second << endl;++it;}cout << endl;for (const auto& e : m2){cout << e.first << ':' << e.second << endl;}cout << endl;return 0;
}

4. insert的使用

- 在
map容器中,insert方法用于插入键值对。插入的返回值是一个pair<iterator, bool>类型的对象,其中包含两个部分。第一个部分是iterator,它指向插入元素的位置;第二部分是bool,表示插入操作是否成功。如果map中已经存在指定的key,则插入会失败,此时返回的bool为false,iterator会指向原来key对应的位置;如果插入成功,则返回true,并且iterator会指向新插入元素的位置。- 由于
map中的key是唯一的,并且必须按照一定的顺序排列,因此,insert操作不仅需要判断元素是否已存在,还要保证元素的排序。如果尝试插入一个已经存在的key,插入操作会被忽略,原来的键值对不会被替换或删除。insert方法还支持通过提供一个迭代器位置来指定插入位置,这个位置是一个建议的插入位置。虽然它作为一个提示会影响插入,但实际的插入位置仍然会由map的排序规则决定。如果建议位置不符合排序规则,插入的元素会被放置到合适的位置。- 此外,
insert方法也支持插入一段迭代器区间,这与set容器类似。通过这种方式,可以一次性插入多个元素。通过提供一个迭代器区间,可以将一系列元素批量插入到map中,而不需要单独进行逐个插入。这样可以提高效率,特别是在处理大量数据时。
#include <iostream>
#include <map>
#include <vector>
using namespace std;int main() {// 创建一个 map 容器,键和值都是 string 类型map<string, string> m;// 插入单个键值对,使用 pairpair<string, string> p("delete", "删除");auto result1 = m.insert(p); // 返回一个 pair<iterator, bool>cout << "Inserted: " << result1.first->first << " -> " << result1.first->second<< ", Insertion successful: " << result1.second << endl;// 插入单个键值对,使用 pair 显式创建m.insert(pair<string, string>("add", "增加"));// 插入单个键值对,使用 make_pairm.insert(make_pair("insert", "插入"));// 插入单个键值对,使用初始化列表(C++11特性)m.insert({ "free", "释放" });// 插入时指定插入位置(建议位置)// 在这里我们指定插入位置是 m.begin(),即 map 的第一个元素位置auto it = m.begin();m.insert(it, make_pair("update", "更新"));// 插入迭代器区间:通过给定一个迭代器区间来批量插入// 创建一个 vector,包含多个 pair 元素vector<pair<string, string>> vec = {{"key1", "value1"},{"key2", "value2"},{"key3", "value3"}};m.insert(vec.begin(), vec.end());// 打印所有键值对cout << "Map contents:" << endl;for (const auto& entry : m) {cout << entry.first << " -> " << entry.second << endl;}return 0;
}
5. empty 和size的使用
判断容器数据是否为空
求容器中数据节大小
map<string, string> m;
pair<string, string> p("delete", "删除");
m.insert(p);
m.insert(pair<string, string>("add", "增加"));
cout << m.empty() << endl;
cout << m.size() << endl;

6. erase的使用

在
map中,erase是一个用来删除元素的函数,提供了多种重载形式。第一种重载形式void erase(iterator position)接受一个迭代器作为参数,并删除该位置的元素。它通过迭代器直接指向需要删除的元素,并将其从map中移除。第二种重载形式size_type erase(const key_type& k)通过给定key删除对应的元素,如果key存在于map中,则删除该键值对并返回1,如果不存在,则返回0,表示没有元素被删除。第三种重载形式void erase(iterator first, iterator last)接受两个迭代器,表示一个区间,删除这个区间内的所有元素。这种形式允许你通过指定一个范围来删除多个元素,它会删除从first到last之间的所有元素,包括first位置的元素,但不包括last位置的元素。
pair<string, string> arr[] = { make_pair("add","增加"),make_pair("delete","删除"),make_pair("insert","插入"),make_pair("free","释放") };map<string, string> m1;
map<string, string> m2(arr, arr + sizeof(arr) / sizeof(arr[0]));m2.erase(m2.begin());
size_t t = m2.erase("delete");
cout << t << endl;
size_t t = m2.erase("aaaa");
cout << t << endl;m2.erase(m2.begin(), m2.end());

7. swap 和 clear的使用


pair<string, string> arr[] = { make_pair("add","增加"),make_pair("delete","删除"),make_pair("insert","插入"),make_pair("free","释放") };map<string, string> m1;map<string, string> m2(arr, arr + sizeof(arr) / sizeof(arr[0]));m2.swap(m1);m1.clear();
交换后
clear()之后
8. find的使用
可以传入key值,如果存在返回对应位置的迭代器,不存在返回end()。
auto it = m2.find("delete");if (it != m2.end()) { cout << "key: " << it->first << " val: " << it->second << endl; }else { cout << "没有对应key值" << endl; };

9. count的使用

count方法返回的是key对应的节点个数。由于在map中,每个key只能对应一个value,所以count的返回值要么是0,要么是1。因此,count返回值使用size_t类型,因为返回值不能为负数,且size_t是一个无符号整数类型,适合表示数量。虽然在map中每个key只有一个或零个节点,但count的设计是为了与multimap保持接口一致,因为在multimap中,key可以对应多个节点,所以调用count时可能返回大于1的值。为了保持统一的接口,map也提供了count方法,尽管在实际使用中,这个方法不常用。通常,map中的查找操作可以通过find来完成,find方法更加高效和直观。总之,count方法虽然存在,但在map中的实际用途较少,更多的是为与multimap的接口一致性提供支持。
pair<string, string> arr[] = { make_pair("add","增加"),make_pair("delete","删除"),make_pair("insert","插入"),make_pair("free","释放") };map<string, string> m1;map<string, string> m2(arr, arr + sizeof(arr) / sizeof(arr[0]));size_t t = m2.count("insert");cout << t << endl;

11. lower_bound 和 upper_bound的使用


都是用于在有序容器(如
set、map)中查找位置的函数:
lower_bound(val):返回指向第一个不小于val(即>= val)的元素的迭代器。upper_bound(val):返回指向第一个大于val(即> val)的元素的迭代器。两者的返回值都是
iterator类型,表示在容器中对应位置的元素;如果没有符合条件的元素(即到达容器末尾),则返回end()。在set中,它们常用于查找区间范围[lower_bound(val), upper_bound(val))。
pair<string, string> arr[] = { make_pair("add","增加"),make_pair("delete","删除"),make_pair("insert","插入"),make_pair("free","释放") };map<string, string> m1;map<string, string> m2(arr, arr + sizeof(arr) / sizeof(arr[0]));// 使用 lower_bound 查找第一个大于等于 "delete" 的元素auto it_lower = m2.lower_bound("delete");if (it_lower != m2.end()) {cout << "lower_bound('delete'): " << it_lower->first << " -> " << it_lower->second << endl;}// 使用 upper_bound 查找第一个大于 "delete" 的元素auto it_upper = m2.upper_bound("delete");if (it_upper != m2.end()) {cout << "upper_bound('delete'): " << it_upper->first << " -> " << it_upper->second << endl;}// 查找区间 ["delete", "insert") 的元素cout << "Range ['delete', 'insert'):" << endl;for (auto it = it_lower; it != it_upper; ++it) {cout << it->first << " -> " << it->second << endl;}

12. equal_range的使用

equal_range是用于在有序容器(如map和multimap)中查找与给定key相等的元素范围的函数。它返回一个pair<iterator, iterator>,其中第一个迭代器指向 第一个等于key的元素,第二个迭代器指向 第一个大于key的元素,即形成一个前闭后开的区间[first, second)。对于map来说,key的值只能有一个或者没有,而对于multimap,由于容器允许多个相同的key,因此equal_range的作用非常重要,它可以返回一个包含所有等于该key的元素的区间。- 尽管
map中的key是唯一的,但equal_range方法的设计依然与multimap保持一致,这是因为equal_range函数的接口需要对multimap和map提供相同的调用方式。在map中,当调用equal_range查找一个key时,它会返回一个包含该key的前闭后开区间[first, second)。例如,如果map中有如下的key值序列1, 5, 7,当我们查找5时,equal_range(5)会返回一个包含5的区间,即[5, 7),其中first是指向5的迭代器,second是指向7的迭代器。- 如果查找的
key不存在于map中,equal_range依然返回一个区间,但这个区间并不包含任何元素。例如,在map中如果查询3,由于3不存在,它会返回[5, 5),即从5到5的空区间。这是因为map的迭代器是按顺序排列的,equal_range会返回一个区间,起始迭代器指向第一个大于3的元素的位置,结束迭代器指向第一个大于3的元素。因此,返回的是一个空区间。- 如果
key比map中所有的元素都小,equal_range会返回一个从first指向map的第一个元素的迭代器,到second指向end()的迭代器的区间。如果key比map中所有的元素都大,equal_range会返回一个从first指向end(),second也是end()的区间,即end()到end()的空区间。
因此,equal_range 在 map 中不仅用于查找已存在的 key,还用于返回一个表示“没有找到元素”的空区间。它返回的区间是前闭后开的,这意味着区间包括了 key 等于 key 的元素,但不包括大于 key 的元素。
总的来说,equal_range 是为了解决多重 key 元素的情况而设计的,与 multimap 保持一致,但在 map 中依然有效,并且常用于通过迭代器操作一个元素的区间。在查找元素时,equal_range 可以帮助我们明确区间的起始和结束位置,即使 key 不存在时,也能返回一个有效的区间,这对于容器的区间操作非常重要。
13. operator= 的使用
为容器分配新的内容
pair<string, string> arr[] = { make_pair("add","增加"),make_pair("delete","删除"),make_pair("insert","插入"),make_pair("free","释放") };map<string, string> m1;
map<string, string> m2(arr, arr + sizeof(arr) / sizeof(arr[0]));m1 = m2;

14. operator[ ] 的使用
- 在
map中,operator[]的工作原理是通过查找给定的key来访问对应的value。如果key已存在,operator[]会返回对应的value引用。如果key不存在,operator[]会通过T()默认构造一个新的value对象,并将其插入到map中,然后返回新插入的value引用。这里的T()是value类型的默认构造函数,它生成一个类型为T的匿名对象,并通过insert方法将该key和新构造的value插入到map中。- 在插入的过程中,如果
key已经存在,insert操作会返回指向该key的迭代器,而不会影响原map中的key和对应的value。如果key不存在,insert会将新的key-value对插入到map中,并返回新插入位置的迭代器。最终,operator[]会通过插入或查找操作获取到key对应的value,并返回value的引用,因为value被存储在pair<const Key, T>结构体中,这个pair存储在map的节点中。因此,
operator[]的行为就是:在[]内输入一个key,返回对应的value引用,允许对该value进行访问和修改。无论是访问已存在的key还是通过operator[]插入新key,都能返回该key对应的value引用,从而直接操作该值。
// 创建一个 map,键为 string,值为 intmap<string, int> m;// 插入一个键值对,使用 operator[] 直接插入m["apple"] = 10;m["banana"] = 20;// 情况 1: 访问已存在的 key,修改对应的 valuecout << "apple: " << m["apple"] << endl; // 输出: apple: 10m["apple"] = 30; // 修改 "apple" 的 valuecout << "apple: " << m["apple"] << endl; // 输出: apple: 30// 情况 2: 访问一个不存在的 key,自动插入一个默认构造的 valuecout << "cherry: " << m["cherry"] << endl; // 输出: cherry: 0// "cherry" 被插入并且默认构造了一个 int 值 0// 打印所有键值对for (const auto& p : m) {cout << p.first << " -> " << p.second << endl;}
二、multimap
multimap是一个关联容器,它按照特定顺序存储由key和value构成的键值对<key, value>,其中key可以重复。与map不同,map中的key是唯一的,而multimap中允许多个相同的key存在。因此,在multimap中,某个key可以对应多个不同的value。multimap的元素总是按照key排序的,这使得它在某些需要排序的场景下非常有用。
2.multimap的底层实现通常是通过平衡二叉搜索树(例如红黑树)来完成的,因此插入和查找元素的时间复杂度通常是 O(log N),与map相同。然而,由于multimap中可能有多个相同的key,它比unordered_multimap容器略慢,后者的元素是无序的,且使用哈希表实现,查找速度通常更快。
3.multimap提供了强大的迭代器遍历能力,用户可以遍历容器中的所有元素,获取与key对应的有序value序列。不同于map,multimap没有提供operator[]。这是因为multimap允许同一个key对应多个不同的value,因此无法确定如果使用operator[]访问时应该返回哪一个value。为了避免这种不确定性,multimap并没有提供operator[],而是使用insert、find和equal_range等方法来访问和操作数据。总结来说,
multimap是一个非常适合存储具有重复key的键值对的容器,它保证了key的有序性,但不提供通过[]操作符访问元素的功能。multimap的设计使得它在处理重复key时更为灵活,但在性能上,相较于unordered_multimap,会稍逊一筹。
1. 模板和类模板的认识
multimap 和 map 的类模板和构造函数非常相似,主要区别在于是否允许 key 的重复。在 map 中,key 必须是唯一的,而在 multimap 中,key 允许重复。这意味着 multimap 允许存储多个具有相同 key 的元素。


接下来就主要讲解和map相同接口不同使用的函数。
2. insert的使用
multimap 允许插入多个具有相同 key 的键值对。与 map 不同,在 map 中每个 key 都是唯一的,而 multimap 允许相同的 key 多次出现。即使 key 相同,value 可以是相同的,也可以是不同的。这使得 multimap 非常适合需要存储重复 key 的场景。
#include <iostream>
#include <map>
using namespace std;int main() {multimap<string, string> mm;// 插入多个相同key的元素mm.insert(make_pair("apple", "fruit"));mm.insert(make_pair("apple", "green"));mm.insert(make_pair("apple", "red"));// 插入不同key的元素mm.insert(make_pair("banana", "yellow"));// 打印 multimap 中的内容for (const auto& p : mm) {cout << p.first << ": " << p.second << endl;}return 0;
}
3. erase的使用
erase 函数用于删除特定 key 对应的元素。在 multimap 中,如果有多个相同的 key,erase 会删除所有匹配的元素,而不仅仅是第一个。这一点与 map 不同,map 中每个 key 只能对应一个元素。删除操作返回值是 size_t 类型,表示删除的元素个数。这允许我们直接知道删除了多少个节点。
#include <iostream>
#include <map>
using namespace std;int main() {multimap<string, string> mm;// 插入数据mm.insert(make_pair("apple", "fruit"));mm.insert(make_pair("apple", "green"));mm.insert(make_pair("apple", "red"));mm.insert(make_pair("banana", "yellow"));// 删除所有key为 "apple" 的元素size_t numErased = mm.erase("apple");cout << "Erased " << numErased << " elements with key 'apple'." << endl;// 打印剩余元素for (const auto& p : mm) {cout << p.first << ": " << p.second << endl;}return 0;
}
4. find的使用
find 函数用于查找指定 key 的第一个匹配元素。在 multimap 中,尽管可能有多个元素的 key 相同,find 只会返回第一个找到的匹配元素的迭代器。这与 map 相同,map 也只能返回一个元素的位置。然而,在 multimap 中,如果需要访问所有与某个 key 对应的元素,可以通过其他方法(如 equal_range)来实现。
#include <iostream>
#include <map>
using namespace std;int main() {multimap<string, string> mm;mm.insert(make_pair("apple", "fruit"));mm.insert(make_pair("apple", "green"));mm.insert(make_pair("banana", "yellow"));// 查找第一个 "apple" 的元素auto it = mm.find("apple");if (it != mm.end()) {cout << "Found key 'apple': " << it->first << " -> " << it->second << endl;} else {cout << "Key not found." << endl;}return 0;
}
5. count的使用
count 函数返回特定 key 对应的元素个数。在 multimap 中,key 可以重复,因此 count 返回的结果是该 key 对应的元素的数量。如果 key 对应多个相同的元素,count 会返回一个大于 1 的值;如果 key 不存在,返回值为 0。这与 map 略有不同,map 中每个 key 只能有一个元素,因此 count 结果要么是 1,要么是 0。
#include <iostream>
#include <map>
using namespace std;int main() {multimap<string, string> mm;mm.insert(make_pair("apple", "fruit"));mm.insert(make_pair("apple", "green"));mm.insert(make_pair("banana", "yellow"));mm.insert(make_pair("banana", "green"));// 统计 "apple" 对应的元素数量size_t countApple = mm.count("apple");cout << "Number of 'apple' elements: " << countApple << endl;// 统计 "banana" 对应的元素数量size_t countBanana = mm.count("banana");cout << "Number of 'banana' elements: " << countBanana << endl;return 0;
}
6. equal_range的使用
equal_range 返回一个迭代器区间,表示 key 对应的所有元素范围。对于 multimap,如果有多个元素的 key 相同,equal_range 会返回一个包含所有这些元素的区间。这意味着,它能够返回多个相同 key 的元素范围,而不仅仅是一个元素。通过该区间,可以直接操作所有与某个 key 相关联的元素。如果 key 不存在,equal_range 会返回一个空区间,这点与 map 类似。
#include <iostream>
#include <map>
using namespace std;int main() {multimap<string, string> mm;mm.insert(make_pair("apple", "fruit"));mm.insert(make_pair("apple", "green"));mm.insert(make_pair("apple", "red"));mm.insert(make_pair("banana", "yellow"));// 查找 "apple" 的区间auto range = mm.equal_range("apple");cout << "Range for 'apple':" << endl;for (auto it = range.first; it != range.second; ++it) {cout << it->first << ": " << it->second << endl;}return 0;
}
总结
在 C++ 中,map、set、multimap 和 multiset 都是非常常用的关联容器,它们用于存储由键和值组成的数据对,并提供高效的查找、插入和删除操作。map 和 set 通过键值进行元素存储,且保证每个键唯一,而 multimap 和 multiset 允许多个相同的键存在。map 和 multimap 分别存储 key-value 对,set 和 multiset 则只存储 key,它们的底层实现通常基于平衡二叉搜索树(如红黑树),确保元素有序。每个容器的使用场景有所不同,map 和 set 适合键值唯一的应用,multimap 和 multiset 则更适合处理有重复键的数据结构。
✨ 坚持用 清晰易懂的图解 + 代码语言, 让每个知识点都 简单直观 !
🚀 个人主页 :不呆头 · CSDN
🌱 代码仓库 :不呆头 · Gitee
📌 专栏系列 :
- 📖 《C语言》
- 🧩 《数据结构》
- 💡 《C++》
- 🐧 《Linux》
/>>💬 座右铭 : “不患无位,患所以立。”




