C++ 关联式容器:map,multimap,set,multiset
目录
引言
一、关联式容器概述
1.1 与序列式容器的区别
1.2 底层结构
二、set容器详解set介绍
2.1 set的特性
2.2 set的模板参数
2.3 set的常用接口
2.4 set使用示例
三、map容器详解map介绍
3.1 map的特性
3.2 map的模板参数
3.3 map的常用接口
3.4 map使用示例
四、multiset容器详解multiset介绍
4.1 multiset的特性
4.2 multiset的模板参数
4.3 multiset的常用接口
4.4 multiset使用示例
五、multimap容器详解multimap介绍
编辑5.1 multimap的特性
5.2 multimap的模板参数
5.3 multimap的常用接口
5.4 multimap使用示例
六、总结
引言
在C++ 的标准模板库(STL)中,关联式容器是非常重要的一部分,它们为我们提供了高效的数据存储和检索方式。今天,我们就来深入探讨一下其中的 map 和 set 容器,看看它们是如何在实际编程中发挥作用的。
一、关联式容器概述
1.1 与序列式容器的区别
在之前的学习中,我们接触过像 vector 、 list 、 deque 这样的序列式容器,它们底层是线性序列的数据结构,存储的是数据本身。而关联式容器存储的是 <key, value> 结构的键值对,在数据检索时比序列式容器效率更高。
1.2 底层结构
关联式容器根据应用场景不同,主要有树形结构(如红黑树)和哈希结构。今天重点讨论的 map 和 set 以及它们的变体 multimap 、 multiset 底层多采用平衡搜索树(红黑树)实现,这使得容器中的元素是有序的序列。
二、set容器详解set介绍
2.1 set的特性
set 是按照一定次序存储元素的容器,其中元素的 value 也标识它自己(即 value 就是 key ),并且每个 value 必须是唯一的。 set 中的元素不能在容器中修改(元素总是 const ),但可以插入或删除。其内部元素默认按照小于来比较排序。
2.2 set的模板参数
cpptemplate <class T,class Compare = less<T>,class Allocator = allocator<T>> class set;
- T :存储元素的类型,实际底层存储 <value, value> 的键值对。
- Compare :比较器类型,默认按小于比较。
- Allocator :空间配置器,一般不用用户传递。
2.3 set的常用接口
1. 插入元素
cpp#include <set>#include <iostream>int main() {std::set<int> s;std::pair<std::set<int>::iterator, bool> ret = s.insert(5);if (ret.second) {std::cout << "插入成功,元素值为:" << *ret.first << std::endl;} else {std::cout << "插入失败,元素已存在" << std::endl;}return 0;}
1. 删除元素
cpp#include <set>#include <iostream>int main() {std::set<int> s = {1, 2, 3, 4, 5};s.erase(s.find(3)); // 删除值为3的元素for (auto e : s) {std::cout << e << " ";}std::cout << std::endl;return 0;}
1. 查找元素
cpp#include <set>#include <iostream>int main() {std::set<int> s = {1, 2, 3, 4, 5};std::set<int>::iterator it = s.find(3);if (it != s.end()) {std::cout << "找到元素:" << *it << std::endl;} else {std::cout << "未找到元素" << std::endl;}return 0;}
2.4 set使用示例
cpp#include <set>#include <iostream>void TestSet() {int array[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4, 6, 8, 0};std::set<int> s(array, array + sizeof(array) / sizeof(array[0]));std::cout << "set的大小为:" << s.size() << std::endl;// 正向打印set中的元素std::cout << "正向打印set元素:";for (auto& e : s) {std::cout << e << " ";}std::cout << std::endl;// 使用迭代器逆向打印set中的元素std::cout << "逆向打印set元素:";for (auto it = s.rbegin(); it != s.rend(); ++it) {std::cout << *it << " ";}std::cout << std::endl;// set中值为3的元素出现了几次std::cout << "值为3的元素个数:" << s.count(3) << std::endl;}int main() {TestSet();return 0;}
三、map容器详解map介绍
3.1 map的特性
map 是关联容器,它按照特定的次序(按照 key 来比较)存储由键值 key 和值 value 组合而成的元素。 key 通常用于排序和唯一地标识元素, value 存储与此键值 key 关联的内容。
3.2 map的模板参数
cpptemplate <class Key,class T,class Compare = less<Key>,class Allocator = allocator<pair<const Key, T>>> class map;
- Key :键值对中 key 的类型。
- T :键值对中 value 的类型。
- Compare :比较器类型,默认按 key 小于比较。
- Allocator :空间配置器。
3.3 map的常用接口
1. 插入元素
cpp#include <map>#include <string>#include <iostream>int main() {std::map<std::string, std::string> m;// 方式一:用pair直接构造键值对插入std::pair<std::map<std::string, std::string>::iterator, bool> ret1 = m.insert(std::pair<std::string, std::string>("apple", "苹果"));if (ret1.second) {std::cout << "插入成功" << std::endl;} else {std::cout << "插入失败,元素已存在" << std::endl;}// 方式二:用make_pair函数构造键值对插入std::pair<std::map<std::string, std::string>::iterator, bool> ret2 = m.insert(std::make_pair("banana", "香蕉"));if (ret2.second) {std::cout << "插入成功" << std::endl;} else {std::cout << "插入失败,元素已存在" << std::endl;}// 方式三:通过operator[]插入m["pear"] = "梨";return 0;}
1. 删除元素
cpp#include <map>#include <string>#include <iostream>int main() {std::map<std::string, std::string> m = {{"apple", "苹果"}, {"banana", "香蕉"}};m.erase("banana");for (const auto& e : m) {std::cout << e.first << " -> " << e.second << std::endl;}return 0;}
1. 查找元素
cpp#include <map>#include <string>#include <iostream>int main() {std::map<std::string, std::string> m = {{"apple", "苹果"}, {"banana", "香蕉"}};std::map<std::string, std::string>::iterator it = m.find("apple");if (it != m.end()) {std::cout << "找到元素:" << it->first << " -> " << it->second << std::endl;} else {std::cout << "未找到元素" << std::endl;}return 0;}
3.4 map使用示例
cpp#include <map>#include <string>#include <iostream>void TestMap() {std::map<std::string, std::string> m;// 向map中插入元素的方式// 将键值对<"peach","桃子">插入map中,用pair直接来构造键值对m.insert(std::pair<std::string, std::string>("peach", "桃子"));// 将键值对<"peach","桃子">插入map中,用make_pair函数来构造键值对m.insert(std::make_pair("banana", "香蕉"));// 借用operator[]向map中插入元素m["apple"] = "苹果";std::cout << "map的大小为:" << m.size() << std::endl;// 用迭代器去遍历map中的元素,可以得到一个按照key排序的序列std::cout << "遍历map元素:" << std::endl;for (const auto& e : m) {std::cout << e.first << " ---> " << e.second << std::endl;}// map中的键值对key一定是唯一的,如果key存在将插入失败auto ret = m.insert(std::make_pair("peach", "桃色"));if (ret.second) {std::cout << "peach,桃色不在map中,已经插入" << std::endl;} else {std::cout << "键值为peach的元素已经存在:" << ret.first->first << " ---> " << ret.first->second << " 插入失败" << std::endl;}// 删除key为"apple"的元素m.erase("apple");if (1 == m.count("apple")) {std::cout << "apple还在" << std::endl;} else {std::cout << "apple被吃了" << std::endl;}}int main() {TestMap();return 0;}
四、multiset容器详解multiset介绍

4.1 multiset的特性

multiset 是按照特定顺序存储元素的容器,其中元素是可以重复的。元素的 value 也会标识它(因为 multiset 中本身存储的就是 <value, value> 组成的键值对),元素的值不能在容器中进行修改(元素总是 const ),但可以从容器中插入或删除。其内部元素默认按照小于来比较排序。
4.2 multiset的模板参数
cpptemplate <class T,class Compare = less<T>,class Allocator = allocator<T>
> class multiset;
与 set 的模板参数类似, T 为存储元素的类型, Compare 是比较器, Allocator 是空间配置器 。
4.3 multiset的常用接口
1. 插入元素
cpp#include <multiset>
#include <iostream>int main() {std::multiset<int> ms;ms.insert(3);ms.insert(3);ms.insert(5);for (auto e : ms) {std::cout << e << " ";}std::cout << std::endl;return 0;
}
1. 删除元素
cpp#include <multiset>
#include <iostream>int main() {std::multiset<int> ms = {1, 3, 3, 5};ms.erase(ms.find(3)); // 删除一个值为3的元素for (auto e : ms) {std::cout << e << " ";}std::cout << std::endl;return 0;
}
4.4 multiset使用示例
cpp#include <set>
#include <iostream>void TestMultiset() {int array[] = {2, 1, 3, 9, 6, 0, 5, 8, 4, 7};std::multiset<int> ms(array, array + sizeof(array) / sizeof(array[0]));for (auto& e : ms) {std::cout << e << " ";}std::cout << std::endl;
}int main() {TestMultiset();return 0;
}
五、multimap容器详解multimap介绍

5.1 multimap的特性

multimap 是关联式容器,它按照特定的顺序,存储由 key 和 value 映射成的键值对 <key, value> ,其中多个键值对之间的 key 是可以重复的。通常按照 key 排序和唯一地标识元素, value 存储与 key 关联的内容。
5.2 multimap的模板参数
cpptemplate <class Key,class T,class Compare = less<Key>,class Allocator = allocator<pair<const Key, T>>
> class multimap;
和 map 的模板参数类似, Key 是键的类型, T 是值的类型, Compare 是比较器, Allocator 是空间配置器。
5.3 multimap的常用接口
1. 插入元素
cpp#include <multimap>
#include <string>
#include <iostream>int main() {std::multimap<std::string, std::string> mm;mm.insert(std::make_pair("fruit", "apple"));mm.insert(std::make_pair("fruit", "banana"));for (const auto& e : mm) {std::cout << e.first << " -> " << e.second << std::endl;}return 0;
}
1. 删除元素
cpp#include <multimap>
#include <string>
#include <iostream>int main() {std::multimap<std::string, std::string> mm = {{"fruit", "apple"}, {"fruit", "banana"}};mm.erase(mm.find("fruit")); // 删除一个key为"fruit"的键值对for (const auto& e : mm) {std::cout << e.first << " -> " << e.second << std::endl;}return 0;
}
5.4 multimap使用示例
cpp#include <multimap>
#include <string>
#include <iostream>void TestMultimap() {std::multimap<std::string, std::string> mm;mm.insert(std::make_pair("person", "Alice"));mm.insert(std::make_pair("person", "Bob"));mm.insert(std::make_pair("animal", "cat"));mm.insert(std::make_pair("animal", "dog"));std::cout << "遍历multimap元素:" << std::endl;for (const auto& e : mm) {std::cout << e.first << " ---> " << e.second << std::endl;}
}int main() {TestMultimap();return 0;
}
容器 | 元素唯一性 | 元素修改 | 底层结构 | 应用场景举例 |
set | 唯一 | 不可修改 | 红黑树 | 红黑树|存储不重复的整数集合,如学生学号集合 |
map | key唯一 | value可修改 | 红黑树 | 红黑树|存储学生学号与成绩的映射关系 |
multiset | 可重复 | 不可修改 | 红黑树 | 统计单词在文本中出现的所有位置(位置可重复) |
multimap | key可重复 | value可修改 | 红黑树 | |红黑树|存储一个班级中所有学生的成绩(可能有重名学生) |
六、总结
set 和 map 作为C++ STL中重要的关联式容器,有着广泛的应用场景。 set 适用于需要存储唯一元素并进行快速查找、排序的场景; map 则适用于需要建立键值对映射关系,通过 key 高效查找 value 的场景。理解它们的特性、接口和底层实现,能帮助我们在实际编程中更高效地使用它们,优化代码性能。希望通过这篇博客,大家能对 set 和 map 有更深入的认识。