揭秘Map与Set的键值奥秘与集合魅力,解锁高效数据魔法

在这里插入图片描述

文章目录

  • 前言
    • ➰一、关联式容器
      • 1.1 关联式容器的概述
      • 1.2 关联式容器的工作原理
      • 1.3 关联式容器的核心特性
    • ➰二、键值对
      • 2.1 键值对的基本概念
      • 2.2 键值对在C++中的实现
    • ➰三、树形结构的关联式容器
      • 3.1 树形结构的特点
      • 3.2 使用场景
    • ➰四、set的使用与定义
      • 4.1 set的基本特性
      • 4.2 set的声明与构造
      • 4.3 set的成员函数
      • 4.4 set的迭代器
      • 4.5 set的使用示例
    • ➰五、multiset的定义与使用
      • 5.1 multiset基本特性
      • 5.2 multiset的声明与构造
      • 5.3 multiset的成员函数
      • 5.4 multiset的自定义排序
      • 5.5 multiset的使用示例
    • ➰六、map的定义与使用
      • 6.1 map的定义
      • 6.2 map的插入元素
      • 6.3 map的查找元素
      • 6.4 map的遍历元素
      • 6.5 map的删除元素
      • 6.6 map的其他成员函数
      • 6.7 map的自定义排序
      • 6.8 map的的使用样例
    • ➰七、multimap的定义与使用
      • 7.1 multimap的定义
      • 7.2 multimap插入元素
      • 7.3 multimap查找元素
      • 7.4 multimap遍历元素
      • 7.5 multimap删除元素
      • 7.6 multimap的其他成员函数
      • 7.7 注意事项
  • 结语


前言

在C++编程的浩瀚宇宙中,标准模板库(STL)犹如一颗璀璨的星辰,为开发者们提供了强大的数据结构和算法支持。而在STL的众多容器中,Map与Set无疑是两颗尤为耀眼的明珠,它们以高效、有序的方式管理着数据,让键值对和集合的处理变得轻松自如。
本文将带你一起深入探索C++ STL中的Map与Set容器,揭开它们高效数据管理的神秘面纱。从基本用法到底层实现原理,再到实际应用中的


➰一、关联式容器

在C++的编程世界中,关联式容器是数据结构领域中的瑰宝,它们不仅提供了高效的数据存储和检索功能,还通过键值对的映射机制,极大地丰富了程序设计的灵活性和多样性。本文将深入探讨C++关联式容器的核心特性、工作原理以及创新应用,为您揭开这些强大工具的神秘面纱。

1.1 关联式容器的概述

C++标准库中的关联式容器主要包括std::mapstd::setstd::multimapstd::multiset等。它们共同的特点是基于键值对(key-value)或纯键(key-only)进行存储和检索,支持高效的查找、插入和删除操作。

  • std::map:基于红黑树实现的有序关联数组,支持高效的键值对查找、插入和删除。
  • std::set:基于红黑树实现的有序集合,只存储唯一的键,支持高效的查找、插入和删除。
  • std::multimap:与std::map类似,但允许键的重复。
  • std::multiset:与std::set类似,但允许键的重复。

1.2 关联式容器的工作原理

关联式容器内部通常使用平衡二叉树(如红黑树)来实现高效的查找、插入和删除操作。这些操作的时间复杂度通常为O(log n),其中n是容器中元素的数量。平衡二叉树通过自动调整树的结构来保持平衡,从而确保操作的高效性。

1.3 关联式容器的核心特性

  1. 有序性:关联式容器中的元素按照键的顺序进行存储,这使得它们非常适合用于需要排序的场景。
  2. 唯一性std::mapstd::set中的键是唯一的,这确保了数据的唯一性和一致性。
  3. 键值对映射std::mapstd::multimap通过键值对的方式存储数据,这使得它们能够轻松地实现数据的映射和查找。
  4. 范围查询:关联式容器支持基于键的范围查询,可以方便地查找某个范围内的所有元素。

➰二、键值对

在C++中,键值对(Key-Value Pair)是一种常见的数据结构,它由一个键(Key)和一个值(Value)组成。这种结构在编程中非常有用,因为它允许你通过键来快速查找、更新或删除与之关联的值。

2.1 键值对的基本概念

  • 键(Key):键是唯一的标识符,用于访问与之关联的值。在C++中,键通常是某种数据类型(如整数、字符串等)的实例。
  • 值(Value):值是存储在键值对中的实际数据。值可以是任何数据类型,包括基本数据类型(如整数、浮点数、字符等)和复杂数据类型(如对象、结构体等)。

2.2 键值对在C++中的实现

在C++中,键值对通常通过以下几种方式实现:

  1. std::mapstd::unordered_map
    • std::map 是一个关联容器,它存储键值对,并根据键的排序顺序自动排序这些对。默认情况下,std::map 使用 < 运算符来比较键。
    • std::unordered_map 是另一个关联容器,它也存储键值对,但不保证元素的顺序。它使用哈希表来实现快速查找、插入和删除操作。
  2. std::pair
    • std::pair 是一个模板类,它创建了一个包含两个数据成员的对象。这两个数据成员分别被称为 firstsecond,可以分别用作键和值。虽然 std::pair 本身不直接实现键值对的存储和查找功能,但它经常与 std::mapstd::unordered_map 或其他容器一起使用来存储键值对。
  3. 自定义数据结构:
    • 在某些情况下,你可能需要创建自己的数据结构来存储键值对。这通常涉及到定义一个类,该类包含两个成员变量(一个用于键,一个用于值),以及必要的成员函数来访问和修改这些成员。

➰三、树形结构的关联式容器

3.1 树形结构的特点

这些树形结构的关联式容器具有以下特点:

  • 有序性:元素根据键的排序顺序进行存储,因此可以像数组一样进行顺序遍历。
  • 平衡性:使用平衡二叉树(如红黑树)来维护元素,从而保证了查找、插入和删除操作的时间复杂度为O(log n)。
  • 自动排序:在插入新元素时,容器会自动将其插入到正确的位置,以保持元素的排序顺序。
  • 键的唯一性(对于std::mapstd::set:这些容器保证键的唯一性,即不允许插入具有相同键的多个元素(对于std::multimapstd::multiset则允许键的重复)。

3.2 使用场景

树形结构的关联式容器在C++中有广泛的应用场景,包括但不限于:

  • 字典和映射std::mapstd::multimap可以用于实现字典和映射,其中键是单词或标识符,值是相应的定义或数据。
  • 集合操作std::setstd::multiset可以用于实现集合操作,如并集、交集和差集等。
  • 排序和去重:这些容器可以用于对元素进行排序和去重操作。
  • 查找和替换:由于这些容器提供了快速的查找操作,因此它们可以用于实现查找和替换功能。

总之,树形结构的关联式容器是C++标准库中非常强大且灵活的数据结构,它们提供了高效的查找、插入和删除操作,并且保证了元素的排序顺序和键的唯一性(对于std::mapstd::set)。

➰四、set的使用与定义

4.1 set的基本特性

  • 存储不重复元素:set中的每个元素都是唯一的,不允许有重复值。
  • 自动排序:set中的元素会按照一定的顺序排列,可以是自然顺序或者根据自定义的比较函数进行排序。
  • 元素不可修改:set中的元素值不能直接被改变,因为元素值就是其键值,关系到set元素的排列规则。
  • 高效操作:set支持快速的查找、插入和删除操作,时间复杂度通常为O(log n),这是由于其底层实现采用红黑树这种平衡二叉搜索树结构。

4.2 set的声明与构造

  • 声明set<typename> name;,其中typename可以是任何基本类型(如int、double、char等),也可以是STL标准容器(如vector、set、queue等)。
  • 构造
    • 默认构造函数:set<typename> name;,创建一个空的set。
    • 拷贝构造函数:set<typename> name(const set<typename>& other);,创建一个新的set,它是现有set的副本。
    • 初始化列表构造:set<typename> name{val1, val2, ...};,使用初始化列表来构造set。
    • 范围构造:set<typename> name(first, last);,使用一个迭代器范围[first, last)来构造set。

4.3 set的成员函数

  • 插入元素
    • insert(const typename& value);:将一个元素插入到set中。如果元素已存在,则插入操作将被忽略。
    • pair<iterator, bool> insert(const typename& value);:返回一个pair,其中iterator指向插入的位置,bool表示插入是否成功。
  • 删除元素
    • erase(iterator pos);:删除迭代器pos指向的元素。
    • erase(const typename& value);:删除值为value的元素。
    • erase(iterator first, iterator last);:删除范围[first, last)内的所有元素。
  • 查找元素
    • find(const typename& value);:查找值为value的元素,返回一个指向该元素的迭代器。如果未找到,则返回end()。
    • count(const typename& value);:返回值为value的元素在set中出现的次数。对于set来说,返回值只能是0或1。
  • 其他成员函数
    • size();:返回set中元素的个数。
    • empty();:判断set是否为空。如果为空,返回true;否则返回false。
    • clear();:清空set中的所有元素。
    • begin();:返回一个指向set中第一个元素的迭代器。
    • end();:返回一个指向set末尾的迭代器(注意,这是一个“尾后迭代器”,不指向任何实际元素)。
    • lower_bound(const typename& value);:返回指向第一个不小于value的元素的迭代器。
    • upper_bound(const typename& value);:返回指向第一个大于value的元素的迭代器。
    • equal_range(const typename& value);:返回一个pair,表示value在set中的范围(即[lower_bound, upper_bound))。

4.4 set的迭代器

set的迭代器是双向迭代器,支持正向和反向遍历。由于set中的元素是有序的,所以迭代器的遍历顺序也是有序的。此外,set的迭代器是const_iterator,这意味着不能通过迭代器直接修改元素的值。

4.5 set的使用示例

以下是一个简单的使用示例,展示了如何创建set、插入元素、查找元素和遍历元素:

#include <iostream>  
#include <set>  
  
using namespace std;  
  
// set的基本使用
void test_set1() {
	// 排序+去重
	set<int> s;
	s.insert(2);
	s.insert(4);
	s.insert(5);
	s.insert(1);
	s.insert(7);
	s.insert(7); // 去重原理:一个值已经有了,我们就不插入
	
	auto it = s.begin();
	while (it != s.end()) {
		cout << *it << " ";
		++it;
	}
	cout << endl;
	
	for (auto e : s) {
		cout << e << " ";
	}
	cout << endl;

	/*auto pos = s.find(3);
	if(pos != s.end())
		s.erase(pos);*/
	s.erase(1);

	for (auto e : s) {
		cout << e << " ";
	}
	cout << endl;
}

// set迭代器的使用
void test_set2() {
	set<int> myset;
	set<int>::iterator itlow, itup;

	for (int i = 1; i < 10; i++)
		myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90

	// 删除[30 60],但是迭代器是左闭右开
	itlow = myset.lower_bound(30);                // 下限 >=     
	itup = myset.upper_bound(60);                 // 上限 >

	// [itlow, itup)
	cout << *itlow << endl;
	cout << *itup << endl;

	myset.erase(itlow, itup);

	for (auto e : myset) {
		cout << e << " ";
	}
	cout << endl;
}

int main(){
    test_set1();
    cout << endl << endl;
    test_set2();
    
	return 0;
}

综上所述,C++中的set是一种非常实用的容器,它提供了高效的查找、插入和删除操作,并且保证了元素的唯一性和有序性。

➰五、multiset的定义与使用

在C++中,multiset是一种非常有用的标准模板库(STL)容器,它用于存储一组按照特定顺序排列的元素,并且允许元素重复。以下是对multiset的详细介绍:

5.1 multiset基本特性

  1. 存储重复元素:与set容器不同,multiset允许存储重复的元素。
  2. 自动排序multiset中的元素会根据一定的顺序(默认是升序)自动进行排序。
  3. 元素不可直接修改multiset中的元素值在插入后不能直接被修改,因为元素值就是其键值,直接修改会破坏容器的有序性。不过,可以通过删除旧元素并插入新元素的方式来间接修改。
  4. 底层实现multiset的底层通常使用红黑树这种平衡二叉搜索树结构来实现,以确保高效的查找、插入和删除操作。

5.2 multiset的声明与构造

  1. 声明multiset<typename> name;,其中typename表示要存储的元素类型。
  2. 构造:
    • 默认构造函数:multiset<typename> name;,创建一个空的multiset
    • 拷贝构造函数:multiset<typename> name(const multiset<typename>& other);,创建一个新的multiset,它是现有multiset的副本。
    • 初始化列表构造:multiset<typename> name{val1, val2, ...};,使用初始化列表来构造multiset
    • 范围构造:multiset<typename> name(first, last);,使用一个迭代器范围[first, last)来构造multiset

5.3 multiset的成员函数

multiset提供了丰富的成员函数来操作容器中的元素,包括但不限于:

  1. 插入元素:
    • insert(const typename& value);:将一个元素插入到multiset中。如果元素已存在,则会在保持有序性的前提下,将新元素插入到已有元素的后面(因为允许重复)。
    • iterator insert(const_iterator position, const typename& value);:在指定位置position前插入一个元素,并返回指向新插入元素的迭代器。如果position是end()迭代器,则元素会被添加到容器的末尾。
    • 还有其他形式的insert函数,如使用范围插入、使用初始化列表插入等。
  2. 删除元素
    • erase(iterator pos);:删除迭代器pos指向的元素。
    • erase(const typename& value);:删除值为value的所有元素。
    • erase(iterator first, iterator last);:删除范围[first, last)内的所有元素。
  3. 查找元素
    • find(const typename& value);:查找值为value的元素,返回一个指向该元素的迭代器。如果未找到,则返回end()迭代器。
    • count(const typename& value);:返回值为value的元素在multiset中出现的次数。
  4. 其他成员函数
    • size();:返回multiset中元素的个数。
    • empty();:判断multiset是否为空。如果为空,返回true;否则返回false。
    • clear();:清空multiset中的所有元素。
    • begin();end();:分别返回一个指向multiset中第一个元素和末尾元素的迭代器(尾后迭代器)。
    • rbegin();rend();:分别返回一个指向multiset中最后一个元素和第一个元素前面的位置的逆向迭代器。
    • lower_bound(const typename& value);:返回指向第一个不小于value的元素的迭代器。
    • upper_bound(const typename& value);:返回指向第一个大于value的元素的迭代器。
    • equal_range(const typename& value);:返回一个pair,表示valuemultiset中的范围(即[lower_bound, upper_bound))。

5.4 multiset的自定义排序

默认情况下,multiset中的元素会按照其类型的默认比较函数(通常是<运算符)进行排序。如果需要自定义排序规则,可以在声明multiset时提供一个自定义的比较函数或比较类。例如:

struct Compare {  
    bool operator()(const int& a, const int& b) const {  
        return a > b; // 降序排序  
    }  
};  
  
multiset<int, Compare> myMultiset;

在这个例子中,我们定义了一个比较类Compare,它重载了operator()来指定降序排序规则。然后,我们使用这个比较类来创建一个multiset对象myMultiset,它将按照降序对元素进行排序。

5.5 multiset的使用示例

以下是一个简单的使用示例,展示了如何创建multiset、插入元素、查找元素和遍历元素:

#include <iostream>  
#include <set>  
  
using namespace std;  
  
int main() {  
    multiset<int> myset;
	multiset<int>::iterator itlow, itup;
	
    // 插入元素,允许重复
	myset.insert(1);
	myset.insert(3);
	myset.insert(1);
	myset.insert(4);
	myset.insert(1);
	myset.insert(1);

	for (auto e : myset) {
		cout << e << " ";
	}
	cout << endl;

	// count返回1的个数
	cout << myset.count(1) << endl;

    // 返回一个pair,表示value在multiset中的范围(即[lower_bound, upper_bound))。
	auto ret = myset.equal_range(1);
	itlow = ret.first;
	itup = ret.second;

	// 删除区间内的所有1
	myset.erase(itlow, itup);

	for (auto e : myset) {
		cout << e << " ";
	}
	cout << endl;
  
    return 0;  
}

➰六、map的定义与使用

在C++中,map是一种非常有用的标准模板库(STL)容器,它用于存储键值对(key-value pairs),其中每个键都是唯一的,并且与一个特定的值相关联。以下是map的使用与定义的详细介绍:

6.1 map的定义

map的定义通常使用以下语法:

map<KeyType, ValueType> mapName;

其中,KeyType表示键的类型,ValueType表示值的类型,mapNamemap对象的名称。

例如,定义一个存储字符串到整数的映射的map

map<string, int> myMap;

6.2 map的插入元素

map中插入元素有多种方法:

  1. 使用insert成员函数:
myMap.insert(pair<string, int>("key1", 100));

或者:

myMap.insert(make_pair("key2", 200));
  1. 使用下标运算符[]直接赋值(如果键不存在,则插入新键值对;如果键已存在,则更新对应的值):
myMap["key3"] = 300;

举例:

void test_map1() {
	map<string, string> dict;
	// 1.有名对象
	pair<string, string> kv1("insert", "插入");
	dict.insert(kv1);
	// 2.匿名对象
	dict.insert(pair<string, string>("sort", "排序"));
	// 3.make_pair
	dict.insert(make_pair("string", "字符串"));
	// 4.C++11 多参数的构造函数的隐式类型转换:构造+拷贝构造优化成一步
	dict.insert({ "list", "双向链表" });

	auto it = dict.begin();
	while (it != dict.end()) {
		cout << it->first << ":" << it->second << " ";
		++it;
	}
	cout << endl;
}

6.3 map的查找元素

可以使用find成员函数来查找元素:

auto it = myMap.find("key1");  
if (it != myMap.end()) {  
    cout << "Found: " << it->first << " => " << it->second << endl;  
} else {  
    cout << "Key not found." << endl;  
}

find函数返回一个迭代器,如果找到了指定的键,则迭代器指向该元素;否则,迭代器等于end()

6.4 map的遍历元素

可以使用迭代器来遍历map中的所有元素:

for (auto it = myMap.begin(); it != myMap.end(); ++it) {  
    cout << it->first << " => " << it->second << endl;  
}

或者使用范围for循环(C++11及以上):

for (const auto& pair : myMap) {  
    cout << pair.first << " => " << pair.second << endl;  
}

6.5 map的删除元素

可以使用erase成员函数来删除元素:

  1. 通过键删除:
myMap.erase("key1");
  1. 通过迭代器删除:
auto it = myMap.find("key2");  
if (it != myMap.end()) {  
    myMap.erase(it);  
}
  1. 删除一个范围内的元素(通过两个迭代器):
auto it_begin = myMap.find("key_start");  
auto it_end = myMap.find("key_end");  
if (it_begin != myMap.end() && ++(it_end.first) != myMap.end()) {  
    myMap.erase(it_begin, it_end);  
}

注意:在删除范围内的元素时,需要确保迭代器是有效的,并且it_end应该指向要删除范围之外的第一个元素的位置(因此需要对it_end的迭代器进行自增操作,但这里需要注意it_end可能是end()迭代器,此时不能自增)。然而,上面的代码示例在逻辑上是有问题的,因为find返回的是单个元素的迭代器,而不是一个可以表示范围的迭代器对。正确的做法应该是使用其他方式来确定要删除的范围,比如使用lower_boundupper_bound函数。

6.6 map的其他成员函数

map还提供了其他有用的成员函数,如:

  • size():返回map中元素的个数。
  • empty():判断map是否为空。
  • clear():清空map中的所有元素。
  • count(const Key& key):返回键为key的元素个数(对于map来说,返回值只能是0或1,因为键是唯一的)。
  • lower_bound(const Key& key)upper_bound(const Key& key):分别返回指向第一个不小于(大于)key的元素的迭代器。
  • equal_range(const Key& key):返回一个pair,表示keymap中的范围(即[lower_bound, upper_bound))。

6.7 map的自定义排序

默认情况下,map中的元素会按照键的升序进行排序。如果需要自定义排序规则,可以在声明map时提供一个自定义的比较函数或比较类。例如:

struct Compare {  
    bool operator()(const int& a, const int& b) const {  
        return a > b; // 降序排序  
    }  
};  
  
map<int, string, Compare> myMap;

在这个例子中,我们定义了一个比较类Compare,它重载了operator()来指定降序排序规则。然后,我们使用这个比较类来创建一个map对象myMap,它将按照降序对键进行排序。

6.8 map的的使用样例

#include <iostream>
using namespace std;

void test_map2() {
	map<string, string> dict;
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("insert", "插入"));

	// 不插入,不覆盖,只看key,右值value不相同无所谓
	dict.insert(make_pair("insert", "xxxxx"));

	auto it = dict.begin();
	while (it != dict.end()) {
		// cout << (*it).first << ":" << (*it).second;
		cout << it->first << ":" << it->second << " ";
		++it;
	}
	cout << endl;

	for (const auto& kv : dict) {
		cout << kv.first << ":" << kv.second << " ";
	}
}

// map.operator[],通过key,返回value
void test_map3() {
	// 统计次数
	string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countmap;
	for (auto e : arr) {
		/*auto it = countmap.find(e);
		if (it == countmap.end()) {
			countmap.insert(make_pair(e, 1));
		}
		else {
			it->second++;
		}*/

		// value_type& operator[](const key_type k)
		countmap[e]++;
	}

	for (const auto& kv : countmap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

void test_map4()
{
	map<string, string> dict;
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("insert", "插入"));

	cout << dict["sort"] << endl; // 查找和读
	dict["map"];                  // 插入
	dict["map"] = "映射,地图";     // 修改
	dict["insert"] = "xxx";       // 修改
	dict["set"] = "集合";         // 插入+修改

	for (const auto& kv : dict){
		cout << kv.first << ":" << kv.second << endl;
	}
}


int main() {
	test_map2();
    cout << endl << endl;
    cout << endl << endl;
    
    test_map3();
    cout << endl << endl;
    cout << endl << endl;
    
    test_map4();
    cout << endl << endl;
    cout << endl << endl;

	return 0;
}

综上所述,map在C++中是一个功能强大的容器,它提供了方便的键值对存储和查找功能,并且支持自定义排序规则。

➰七、multimap的定义与使用

在C++中,multimap是一个关联容器,它与map相似,但允许键值对中的键可以重复。以下是对multimap的定义与使用的详细介绍:

7.1 multimap的定义

multimap的定义通常使用以下语法:

multimap<KeyType, ValueType> multimapName;

其中,KeyType表示键的类型,ValueType表示值的类型,multimapNamemultimap对象的名称。

例如,定义一个存储字符串到整数的映射的multimap

multimap<string, int> myMultimap;

7.2 multimap插入元素

multimap中插入元素有多种方法,通常使用insert成员函数:

myMultimap.insert(pair<string, int>("key1", 100));

或者:

myMultimap.insert(make_pair("key2", 200));

由于multimap允许键重复,因此可以插入多个具有相同键的元素。

7.3 multimap查找元素

查找元素时,可以使用find成员函数,但需要注意的是,find函数只返回第一个找到的具有指定键的元素。如果需要查找所有具有相同键的元素,可以使用equal_rangelower_boundupper_bound成员函数。

  • find成员函数:
auto it = myMultimap.find("key1");  
if (it != myMultimap.end()) {  
    cout << "Found: " << it->first << " => " << it->second << endl;  
} else {  
    cout << "Key not found." << endl;  
}
  • equal_range成员函数:返回一个pair,其中first成员是指向第一个不小于给定键的元素的迭代器,second成员是指向第一个大于给定键的元素的迭代器。这可以用于查找所有具有相同键的元素。
auto range = myMultimap.equal_range("key1");  
for (auto it = range.first; it != range.second; ++it) {  
    cout << it->first << " => " << it->second << endl;  
}
  • lower_boundupper_bound成员函数:分别返回指向第一个不小于(大于)给定键的元素的迭代器。
auto lb = myMultimap.lower_bound("key1");  
auto ub = myMultimap.upper_bound("key1");  
for (auto it = lb; it != ub; ++it) {  
    cout << it->first << " => " << it->second << endl;  
}

7.4 multimap遍历元素

可以使用迭代器来遍历multimap中的所有元素:

for (auto it = myMultimap.begin(); it != myMultimap.end(); ++it) {  
    cout << it->first << " => " << it->second << endl;  
}

或者使用范围for循环(C++11及以上):

for (const auto& pair : myMultimap) {  
    cout << pair.first << " => " << pair.second << endl;  
}

7.5 multimap删除元素

可以使用erase成员函数来删除元素:

  1. 通过键删除(删除所有具有指定键的元素):
myMultimap.erase("key1");
  1. 通过迭代器删除:
auto it = myMultimap.find("key2");  
if (it != myMultimap.end()) {  
    myMultimap.erase(it); // 注意:这将只删除找到的第一个元素,如果有多个相同键的元素,需要额外处理  
}

注意:上面的代码只会删除找到的第一个具有指定键的元素。如果需要删除所有具有相同键的元素,应该使用equal_rangelower_boundupper_bound来找到所有相关元素,并逐个删除。

  1. 删除一个范围内的元素(通过两个迭代器):
auto it_begin = myMultimap.lower_bound("key_start");  
auto it_end = myMultimap.upper_bound("key_end");  
myMultimap.erase(it_begin, it_end);

7.6 multimap的其他成员函数

multimap还提供了其他有用的成员函数,如:

  • size():返回multimap中元素的个数。
  • empty():判断multimap是否为空。
  • clear():清空multimap中的所有元素。
  • count(const Key& key):返回键为key的元素个数(对于multimap来说,这个值可能大于1)。

7.7 注意事项

  • multimap中的元素是按照键的顺序存储的,默认情况下是按照键的升序进行排序。如果需要自定义排序规则,可以在声明multimap时提供一个自定义的比较函数或比较类。
  • 由于multimap允许键重复,因此在插入、查找和删除元素时需要特别注意处理多个相同键的情况。

综上所述,multimap在C++中是一个功能强大的容器,它提供了方便的键值对存储和查找功能,并且支持自定义排序规则和处理多个相同键的情况。


结语

最后,需要强调的是,虽然Map与Set提供了高效的数据管理方式,但在使用时仍需注意其性能特点和适用场景。只有深入了解并合理利用这些容器的特性,我们才能在程序中充分发挥它们的作用,实现更加高效、稳定的数据管理。希望本文能够为你提供有益的参考和帮助,让你在C++编程的道路上更加游刃有余。
在这里插入图片描述

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,17的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是17前进的动力!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/895333.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

centOS实用命令

一、查看进程&#xff0c;端口占用 netstat命令(window和linux通用&#xff0c;细节不同) 查看端口占用(linux) netstat -ano |grep 8080查看端口占用(window) netstat -ano |findstr 8080ps命令 可以直接使用ps aux查看所有用户的进程信息 一些参数 参数解释-p根据进程P…

【D3.js in Action 3 精译_034】4.1 D3 中的坐标轴的创建(中篇):定义横纵坐标轴的比例尺

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

企业资产安全之数据防泄密要领

在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。然而&#xff0c;随着数据价值的增加&#xff0c;数据泄露的风险也随之上升。从内部员工的无意泄露到外部黑客的恶意攻击&#xff0c;企业数据安全面临着前所未有的挑战。SDC沙盒数据防泄密解决方案&#xff0c;正是为…

用 Python 构建高级配对交易策略

作者&#xff1a;老余捞鱼 原创不易&#xff0c;转载请标明出处及原作者。 写在前面的话&#xff1a; 本文阐述通过分析加密货币和传统金融工具之间的相关性和协整性&#xff0c;以及实施 Z-score 方法来生成交易信号&#xff0c;然后介绍如何使用 Python 构建配对交易策…

无人机搭载激光雷达在地形测绘中的多元应用

一、高精度地形测量 无人机激光雷达能够发射激光脉冲并接收其回波&#xff0c;通过精确计算激光脉冲的往返时间来确定目标物的距离。这一特性使得无人机激光雷达在地形测绘中能够实现高精度的三维地形测量。通过快速获取大量地形数据&#xff0c;可以生成高精度的数字高程模型…

VScode背景更改

效果 实现方法 第0步 以管理员身份运行VScode 首先 需要安装这个扩展 然后 接下来 找到配置文件 再后来 在配置文件的下面但不超过最后一个大括号的地方加入以下内容 "update.enableWindowsBackgroundUpdates": true,"background.fullscreen": {…

Gee引擎配置微端后登录游戏黑屏怎么办?

GEE引擎配置微端后登录游戏黑屏怎么办&#xff1f;今天飞飞和你们分享GEE引擎配置微端后游戏黑屏的解决办法&#xff0c;希望可以帮助到你~ 1、端口不对 微端没有更新&#xff0c;玩家进入游戏是地图跟装备都看不见&#xff0c;是漆黑的&#xff0c;微端显示连接失败&#xff…

Leecode刷题之路第26天之删除有序数组中的重复项

题目出处 26-删除有序数组中的重复项-题目出处 题目描述 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元…

鸿蒙网络编程系列31-使用RCP调用OpenAI接口实现智能助手

简介 在OpenAI推出GPT系列大模型以后&#xff0c;市场上各种类似的大模型也层出不穷&#xff0c;这些大模型也基本都会兼容OpenAI的接口&#xff0c;在开发基于大模型的应用时&#xff0c;选择使用OpenAI接口作为和后端大模型通讯的标准&#xff0c;可以更好的适配不同厂家的模…

2024年五一杯数学建模C题煤矿深部开采冲击地压危险预测求解全过程论文及程序

2024年五一杯数学建模 C题 煤矿深部开采冲击地压危险预测 原题再现&#xff1a; “煤炭是中国的主要能源和重要的工业原料。然而&#xff0c;随着开采深度的增加&#xff0c;地应力增大&#xff0c;井下煤岩动力灾害风险越来越大&#xff0c;严重影响着煤矿的安全高效开采。在…

一个人如何开发一款App软件

个人开发软件和公司开发软件不一样&#xff0c;其中就是收费上&#xff0c;个人开发的费用低&#xff0c;售后服务态度好啊。一个人负责开发也负责售后&#xff0c;客户就你一个。一般都是工作室和个人接单的多&#xff0c;不是太大的项目就建议是个人开发吧&#xff0c;因为能…

网络编程(21)——通过beast库快速实现http服务器

目录 二十一、day21 1. 头文件和作用域重命名 2. reponse时调用的一些函数 3. http_connection a. 构造函数 b. start() c. process_request() d. create_response() e. create_post_response() f. write_response() 4. Server 5. 主函数 6. 测试 1&#xff09;测…

零基础入门人工智能,如何利用AI工具提升你的学习效率?

在这个信息爆炸的时代&#xff0c;人工智能&#xff08;AI&#xff09;不仅是技术行业的热词&#xff0c;更是我们日常生活中不可或缺的部分。你是否也想过&#xff0c;如何更有效地学习和利用这些强大的AI工具来提升自己的学习效率&#xff1f;今天&#xff0c;我们将介绍六款…

electron本地OCR实现

使用tesseract.js - npm (npmjs.com) 官方demo&#xff1a;GitHub - Balearica/tesseract.js-electron: An example to use tesseract.js in electron 目录结构&#xff1a; // 引入 <script type"module" src"./ocr/tesseract.js"></script>…

垃圾收集器与内存分配机制(三)

目录 学习前言 一、低延迟垃圾收集器 1. Shenandoah收集器 二、ZGC 1. 内存布局 2. 更巧妙的并发整理 三、其他垃圾收集器 学习前言 除了之前我们所学习的经典垃圾收集器除外&#xff0c;我们还有一些低延迟垃圾收集等&#xff01; 之前所学经典垃圾收集器&#xff0c;…

ubuntu 安装nginx

sudo apt-get update sudo apt-get install nginx sudo nginx -vsudo systemctl status nginx sudo systemctl start nginx sudo systemctl stop nginx sudo systemctl restart nginx#浏览器输入&#xff1a;http://192.168.31.181/#查看文件结构 cd /etc/nginx sudo cp nginx.…

瑞云快图云渲染怎么样?渲染一张图贵吗?

在如今的数字时代&#xff0c;云渲染已经成为了设计师和建筑师们不可或缺的工具。而瑞云快图作为一款备受瞩目的云渲染平台&#xff0c;以其出色的性能和实惠的价格吸引了众多用户。 那么&#xff0c;瑞云快图云渲染究竟怎么样&#xff1f;渲染一张图贵吗&#xff1f;本文将为…

kernel32.dll下载地址:如何安全地恢复系统文件

关于从网络上寻找kernel32.dll的下载地址&#xff0c;这通常不是一个安全的做法&#xff0c;而且可能涉及到多种风险。kernel32.dll是Windows操作系统的核心组件之一&#xff0c;负责内存管理、进程和线程管理以及其他关键系统功能。因为kernel32.dll是系统的基础文件&#xff…

初试PostgreSQL数据库

文章目录 一、PostgreSQL数据库概述1.1 PostgreSQL的历史1.2 PostgreSQL安装1.3 安装PostgreSQL二、PostgreSQL起步2.1 连接数据库2.1.1 SQL Shell2.1.2 执行SQL语句2.2 pgAdmin 42.2.1 打开pgAdmin 42.2.2 查找数据库2.2.3 打开查询工具2.2.4 执行SQL语句三、实战小结文章目录…

使用cmdline-tools安装Android SDK与NDK

1.下载SDK工具: www.android.com 选择下载平台包 同意并下载Command Line Tools 下载中 下载完成后解压 2. 创建android sdk目录并复制sdk工具 创建目录