当前位置: 首页 > news >正文

【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中的两种关键关联容器:mapmultimapmap存储唯一的键值对,提供快速的查找、插入和删除操作,时间复杂度为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. 类模板认识

在这里插入图片描述

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

这个构造函数允许你从一个输入范围(由迭代器 firstlast 定义)初始化 map。即你可以通过一对迭代器将一个序列(如 vectorlist 等)中的元素复制到新的 map 中。InputIterator 是一个模板参数,表示输入范围的迭代器类型。firstlast 是两个迭代器,定义了一个范围,map 会将该范围中的元素插入到自己内部。和第一个构造函数一样,key_compareallocator_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的使用

  1. map 容器中的元素是 pair 类型的结构对象,而不像其他容器(如 vectorlist)那样直接存储数据。在 map 中,每个元素都包含两个部分:键(key)和值(value),它们被存储在一个 pair<const Key, T> 结构中。

因此,map 的迭代器和其他容器的迭代器有所不同。虽然迭代器仍然遵循基本的框架,但我们获取的元素是一个 pair 对象,而不是单一的值。

  1. map 中,迭代器解引用后得到的是一个 pair 结构。我们可以通过该结构访问其中的 firstsecond,即 keyvalue。这两者分别存储在 pairfirstsecond 成员中。
  2. 由于 map 的迭代器实际上是指向 pair 结构的指针,因此可以通过 -> 运算符来访问 pair 的成员变量。使用箭头运算符比直接解引用并访问成员要简洁得多。实际上,map 的迭代器已经重载了箭头 -> 运算符,使得它能够直接访问 pair 结构的成员。
  3. 由于 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的使用

在这里插入图片描述

  1. map 容器中,insert 方法用于插入键值对。插入的返回值是一个 pair<iterator, bool> 类型的对象,其中包含两个部分。第一个部分是 iterator,它指向插入元素的位置;第二部分是 bool,表示插入操作是否成功。如果 map 中已经存在指定的 key,则插入会失败,此时返回的 boolfalseiterator 会指向原来 key 对应的位置;如果插入成功,则返回 true,并且 iterator 会指向新插入元素的位置。
  2. 由于 map 中的 key 是唯一的,并且必须按照一定的顺序排列,因此,insert 操作不仅需要判断元素是否已存在,还要保证元素的排序。如果尝试插入一个已经存在的 key,插入操作会被忽略,原来的键值对不会被替换或删除。
  3. insert 方法还支持通过提供一个迭代器位置来指定插入位置,这个位置是一个建议的插入位置。虽然它作为一个提示会影响插入,但实际的插入位置仍然会由 map 的排序规则决定。如果建议位置不符合排序规则,插入的元素会被放置到合适的位置。
  4. 此外,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) 接受两个迭代器,表示一个区间,删除这个区间内的所有元素。这种形式允许你通过指定一个范围来删除多个元素,它会删除从 firstlast 之间的所有元素,包括 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的使用

在这里插入图片描述
在这里插入图片描述

都是用于在有序容器(如 setmap)中查找位置的函数:

  • 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的使用

在这里插入图片描述

  1. equal_range 是用于在有序容器(如 mapmultimap)中查找与给定 key 相等的元素范围的函数。它返回一个 pair<iterator, iterator>,其中第一个迭代器指向 第一个等于 key 的元素,第二个迭代器指向 第一个大于 key 的元素,即形成一个前闭后开的区间 [first, second)。对于 map 来说,key 的值只能有一个或者没有,而对于 multimap,由于容器允许多个相同的 key,因此 equal_range 的作用非常重要,它可以返回一个包含所有等于该 key 的元素的区间。
  2. 尽管 map 中的 key 是唯一的,但 equal_range 方法的设计依然与 multimap 保持一致,这是因为 equal_range 函数的接口需要对 multimapmap 提供相同的调用方式。在 map 中,当调用 equal_range 查找一个 key 时,它会返回一个包含该 key 的前闭后开区间 [first, second)。例如,如果 map 中有如下的 key 值序列 1, 5, 7,当我们查找 5 时,equal_range(5) 会返回一个包含 5 的区间,即 [5, 7),其中 first 是指向 5 的迭代器,second 是指向 7 的迭代器。
  3. 如果查找的 key 不存在于 map 中,equal_range 依然返回一个区间,但这个区间并不包含任何元素。例如,在 map 中如果查询 3,由于 3 不存在,它会返回 [5, 5),即从 55 的空区间。这是因为 map 的迭代器是按顺序排列的,equal_range 会返回一个区间,起始迭代器指向第一个大于 3 的元素的位置,结束迭代器指向第一个大于 3 的元素。因此,返回的是一个空区间。
  4. 如果 keymap 中所有的元素都小,equal_range 会返回一个从 first 指向 map 的第一个元素的迭代器,到 second 指向 end() 的迭代器的区间。如果 keymap 中所有的元素都大,equal_range 会返回一个从 first 指向 end()second 也是 end() 的区间,即 end()end() 的空区间。

因此,equal_rangemap 中不仅用于查找已存在的 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[ ] 的使用

  1. map 中,operator[] 的工作原理是通过查找给定的 key 来访问对应的 value。如果 key 已存在,operator[] 会返回对应的 value 引用。如果 key 不存在,operator[] 会通过 T() 默认构造一个新的 value 对象,并将其插入到 map 中,然后返回新插入的 value 引用。这里的 T()value 类型的默认构造函数,它生成一个类型为 T 的匿名对象,并通过 insert 方法将该 key 和新构造的 value 插入到 map 中。
  2. 在插入的过程中,如果 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

  1. multimap 是一个关联容器,它按照特定顺序存储由 keyvalue 构成的键值对 <key, value>,其中 key 可以重复。与 map 不同,map 中的 key 是唯一的,而 multimap 中允许多个相同的 key 存在。因此,在 multimap 中,某个 key 可以对应多个不同的 valuemultimap 的元素总是按照 key 排序的,这使得它在某些需要排序的场景下非常有用。
    2.multimap 的底层实现通常是通过平衡二叉搜索树(例如红黑树)来完成的,因此插入和查找元素的时间复杂度通常是 O(log N),与 map 相同。然而,由于 multimap 中可能有多个相同的 key,它比 unordered_multimap 容器略慢,后者的元素是无序的,且使用哈希表实现,查找速度通常更快。
    3.multimap 提供了强大的迭代器遍历能力,用户可以遍历容器中的所有元素,获取与 key 对应的有序 value 序列。不同于 mapmultimap 没有提供 operator[]。这是因为 multimap 允许同一个 key 对应多个不同的 value,因此无法确定如果使用 operator[] 访问时应该返回哪一个 value。为了避免这种不确定性,multimap 并没有提供 operator[],而是使用 insertfindequal_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 中,如果有多个相同的 keyerase 会删除所有匹配的元素,而不仅仅是第一个。这一点与 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++ 中,mapsetmultimapmultiset 都是非常常用的关联容器,它们用于存储由键和值组成的数据对,并提供高效的查找、插入和删除操作。mapset 通过键值进行元素存储,且保证每个键唯一,而 multimapmultiset 允许多个相同的键存在。mapmultimap 分别存储 key-value 对,setmultiset 则只存储 key,它们的底层实现通常基于平衡二叉搜索树(如红黑树),确保元素有序。每个容器的使用场景有所不同,mapset 适合键值唯一的应用,multimapmultiset 则更适合处理有重复键的数据结构。


✨ 坚持用 清晰易懂的图解 + 代码语言, 让每个知识点都 简单直观
🚀 个人主页 :不呆头 · CSDN
🌱 代码仓库 :不呆头 · Gitee
📌 专栏系列

  • 📖 《C语言》
  • 🧩 《数据结构》
  • 💡 《C++》
  • 🐧 《Linux》
    />>💬 座右铭“不患无位,患所以立。”在这里插入图片描述
http://www.dtcms.com/a/613525.html

相关文章:

  • 如何利用国外网站开发客户wordpress的免费模板
  • C++、Java 还是测试开发?
  • Java 开发 - 粘包处理器 - 基于消息头 + 消息体(魔数验证、长度验证)
  • Spring Cloud Data Flow 简介
  • 前端性能优化指标,首次内容绘制与交互时间
  • MySQL :实用函数、约束、多表查询与事务隔离
  • 【Java架构师体系课 | MySQL篇】③ Explain执行计划详解
  • Bugku-web题目-xxx二手交易市场
  • 织梦 图片网站武冈 网站建设
  • WebForms Button:深入解析与最佳实践
  • 深度学习实战(基于pytroch)系列(二十)二维卷积层
  • 每日两道算法(2)
  • Ajax 数据请求:从 XMLHttpRequest 到现代前端数据交互的演进
  • Docker 容器连接
  • 手机网站的必要性建设网络平台 请示
  • Vue3 实现 12306 原版火车票组件:从像素级还原到自适应适配【源码】
  • 玄机-第八章 内存马分析-java03-fastjson
  • 人工智能算法优化YOLO的目标检测能力
  • 网站建设常用的编程语言apache设置网站网址
  • 漳州市网站建设费用p2p的网站开发
  • JAVA之二叉树
  • Gitee完全新手教程
  • 具身智能-8家国内外典型具身智能VLA模型深度解析
  • Go 边缘计算在智能汽车产业的应用
  • (五)自然语言处理笔记——迁移学习
  • 长春网站设计长春网络推广项目计划书包含哪些内容
  • ubuntu 25.10 安装Podman
  • 工业自动化核心系统与概念综述
  • 一步一步学习使用LiveBindings() TListView的进阶使用()
  • 全爱科技携智能计算解决方案亮相高交会