STL库:map和set

article/2025/9/30 15:07:56

STL库:map和set

文章目录

  • STL库:map和set
    • 1.STL库中set的官方介绍
    • 2.set的常用接口
    • 3.set的总结
    • 4.STL库中multiset的官方介绍
    • 5.STL库中map的官方介绍
    • 6.map中的键值对pair
    • 7.map的常用接口
      • 7.1 map的访问操作
      • 7.2 map的修改操作
      • 7.3 map的查找操作
    • 8.map的总结
    • 9.STL库中multimap的官方介绍


1.STL库中set的官方介绍

请添加图片描述

  1. T:set(集合)中存放元素的类型,实际在底层存储的是 <value, value> 键值对
  2. Compare:比较器的类型,set中元素默认按照小于(< 升序)来比较。一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(比如自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
    • 小于(< 升序),less
    • 大于(> 降序),定义set时模板参数中要写上 greater
  3. Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理
  4. 使用set时,需要包含头文件 #include

2.set的常用接口

2.1 set的迭代器

  1. begin():返回指向set中第一个元素的迭代器
  2. end():返回指向set中最后一个元素后面的迭代器

2.2 set的修改操作

  1. insert():Insert element(插入元素)
  2. erase():Erase elements(删除元素)

2.3 set的查询操作

  1. find():如果找到,则返回该元素的迭代器,否则返回set::end的迭代器

使用举例:

void test_set1()
{// 用数组array中的元素构造setint array[] = { 1, 3, 5, 4, 2 };set<int> s(array, array + sizeof(array) / sizeof(array[0]));s.insert(4); // 4已经在set中了,不会插入cout << s.size() << endl; // 获取set元素个数// 迭代器遍历setset<int>::iterator it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;// 两种查找元素方式:// 1、algorithm文件中的find函数,底层是暴力查找,全部节点遍历一遍,效率低,O(N)// auto ret = find(s.begin(), s.end(), 4); // 2、set的成员函数,代价为:O(logN)auto ret = s.find(4); // 这里需要判断一下,若找到,返回该元素的迭代器,若没有找到,返回s中最后一个元素后面的迭代器if (ret != s.end()){s.erase(ret); // 删除元素方式1,删除迭代器ret指向的元素}s.erase(5); // 删除元素方式2:删除值为5的元素
}

3.set的总结

  1. 与 map/multimap 不同,map/multimap中存储的是真正的键值对<key, value>,而 set 中只放 value,但在底层实际存放的是由 <value, value> 构成的键值对
  2. set 中插入元素时,只需要插入 value 即可,不需要构造键值对
  3. set 中的元素不可以重复(因此可以使用 set 进行去重)
  4. 使用 set 的迭代器遍历 set 中的元素,可以得到有序序列
  5. set 中的元素默认按照小于来比较
  6. set 中查找某个元素,时间复杂度为:O(log2N),set 中增删查改都是O(log2N)
  7. set 中的元素不允许修改。因为set要保证其有序,因此set中元素不能被直接修改,若要修改可以先删除,在插入
  8. set 中的底层是使用平衡二叉搜索树(红黑树)来实现

核心关键:set排序+去重,只放value,底层是红黑树(平衡二叉搜索树)


4.STL库中multiset的官方介绍

  1. multiset 的使用和 set 几乎一样,它们之间的区别就是:set 是不允许数据冗余的,而 multiset 允许数据冗余,可以有多个相同值的元素
  2. 注意:multiset 中 find() 查找一个值,比如查找4,找到第一个4以后,不能停止,要继续查找到中序的第一个4,即找到第一个4以后,要继续看它的左孩子是不是4,如果不是,就返回当前这个4;如果是,则走到左孩子这个4,继续往下遍历和判断
multiset<int> s;
s.insert(4);
s.insert(3);
s.insert(5);
s.insert(4);
s.insert(6);
s.insert(4);
s.insert(2);// 遍历multiset
for (auto e : s)
{cout << e << " ";
}
cout << endl;// 运行结果:2 3 4 4 4 5 6

如果想要查看容器中,某个值为key的元素有多少个,可以用 count() 接口:

cout << s.count(4) << endl; // 运行结果:3
cout << s.count(3) << endl; // 运行结果:1

5.STL库中map的官方介绍

请添加图片描述

  1. key:键值对中 key 的类型
  2. T: 键值对中 value 的类型
  3. Compare:比较器的类型,map中的元素是按照 key 来比较的,缺省情况下按照小于 ( < 升序) 来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(比如自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
    • 小于(< 升序),less
    • 大于(> 降序),定义map时模板参数中要写上 greater
  4. Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器
  5. 在使用map时,需要包含头文件 #include
  6. 核心:map的所有操作都是通过查找匹配元素的键 key 来完成的,和其对应映射值 value 无关。因为 map 不允许数据冗余,所以每个元素的 key 值是唯一的

6.map中的键值对pair

请添加图片描述

pair用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量 key 和 value,key 代表键值,value 表示与 key 对应的信息

SGI-STL中关于键值对的定义:map中存放的元素是一个个的键值对(即 pair 对象),如下举例:

// map中存的是一个pair结构体,key和value被封装在里面
template <class T1, class T2>
struct pair
{typedef T1 first_type;  // 键值对中key的类型typedef T2 second_type; // 键值对中value的类型T1 first;  // first相当于keyT2 second; // second相当于valuepair(): first(T1()), second(T2()) {} // 构造函数pair(const T1& a, const T2& b): first(a), second(b) {} // 拷贝构造函数
};

构造一个pair对象(键值对):

std::pair<int, int> p(10, 20);

利用 make_pair 函数模板构造一个pair对象(键值对),通过传递给make_pair的参数隐式推导出来

std::pair<int,int> p = std::make_pair(10,20); // 常用这种构造方式

7.map的常用接口

7.1 map的访问操作

  1. operator[]:Access element(访问元素)
  2. at(C++11): Access element(访问元素)
  3. map::at在元素存在时和map::operator[]具有相同的行为,区别在于,当元素不存在时,map::at会抛出异常

1.operator[]

  • 前面学习的 vector 容器里面的 vector::operator[] 是传入元素下标,返回对该元素的引用
  • 而 map 中的 operator[] 访问元素函数,和其它容器有挺大区别的,已经不是传统的数组下标访问了
  • operator[] 底层实际上调用的 insert() 函数

请添加图片描述

map容器中的 map::operator[] 是传入键值 key,通过该元素的 key 查找并判断是否在 map 中:

  1. 如果在 map 中,说明 insert 插入失败,insert函数返回的 pair 对象会带出指向该元素的迭代器,通过这个迭代器,我们可以拿到该元素 key 对应的映射值 value,然后函数返回其对应映射值 value 的引用
  2. 如果不在 map 中,说明 insert 插入成功,插入了这个新元素 < key, value() >,然后函数返回其对应映射值 value 的引用
  3. 注意:这里插入新元素时,该 value() 是一个缺省值,是调用 value 类型的默认构造函数构造的一个匿名对象。(比如是 string 类型就调用 string 的默认构造)

对于operator的总结:使用 map::operator[] 函数,传入元素的键值 key

  1. 如果 key 在map中,返回 key 对应映射值 value 的引用
  2. 如果 key 不在map中,插入该元素 < key, value() >,返回 key 对应映射值 value 的引用
  3. 拿到函数返回的映射值 value,我们可以对其修改
  4. operator[]非常强大,既有查找功能,也有插入功能,还可以修改
map<string, string> dict;//operator[]插入、修改功能
// 这里的意思是,先插入pair("tree", ""),再修改"tree"对应的value值为"树"
dict["tree"] = "树";// 等价于:
dict["tree"];        // 插入pair("string", "")
dict["tree"] = "树"; // "tree"已存在,修改了"tree"对应的value值为"树"

7.2 map的修改操作

请添加图片描述

  1. insert():Insert element(插入元素)
  2. erase(): Erase elements(删除元素)
pair<iterator,bool> insert (const value_type& val);//函数原型

功能:向 map 中插入元素(pair对象)时,先通过该元素的 key 查找并判断是否在 map 中:

  1. 如果在,返回一个 pair 对象:<指向该元素的迭代器, false>
  2. 如果不在,插入该元素<key, value>,返回一个 pair 对象:<指向该元素的迭代器, true>

使用举例:

//实现一个字典 – 可通过单词查找到对应的中文含义
//定义map,向map中插入元素(键值对),map有两种插入元素方式:一般用第二种// 定义map
map<string, string> dict;// 向map中插入元素,2种方式:
// 1、将键值对<"sort", "排序">插入map中,直接构造pair匿名对象(键值对)
dict.insert(pair<string, string>("sort", "排序"));// 2、将键值对<"sort", "排序">插入map中,用make_pair函数来构造pair对象(键值对)
dict.insert(make_pair("left", "左边"));
dict.insert(make_pair("tree", "树"));//-----------------------------------------------------------------------//用迭代器遍历map元素:
//需要注意的是,遍历map中元素的方式和其它迭代器有些不同,下面这种是错误示范// error:这里的it是指向当前元素的迭代器,解引用*it是一个pair对象(键值对),而map中没有流插入运算符的重载,所以不能这样输出
map<string, string>::iterator it = dict.begin();
while (it != dict.end())
{/* * 这里调用的是 it.operator*() 解引用运算符重载函数,* 所以 *it 只是得到了当前节点中存储 pair<key,value> 结构体* key和value是一起封装在pair结构体中的,不能直接把key和value输出出来* 除非重载了专门针对输出 pair<key,value> 结构体中数据的流插入运算符,比如:* ostream& operator<<(ostream& out, const pair<K, V>& kv);*/// cout << *it << endl; // errorit++;
}//------------------------------------------------------------------------//迭代器遍历map元素的两种方式:
// 迭代器遍历map
map<string, string>::iterator it = dict.begin();
while (it != dict.end())
{//遍历map中元素的方式:/** 1、* 迭代器是像指针一样的类型* 对当前元素的迭代器it解引用(*it)可以得到当前节点中存储的数据:即pair对象(键值对),* 然后用'.'再去访问pair对象中的kv值* 这里调用的是it.operator*() 解引用运算符重载函数,返回值为:pair对象的引用*/cout << (*it).first << ", " << (*it).second << endl;/* * 2、* 迭代器箭头->,返回当前迭代器指向j的地址(指针):pair<string, int>** 实际上是调用的operator->()函数* 该指针再使用'->'就可以取到(pair对象)里面的kv值,即first和second* 代码为:it->->first,但可读性太差,编译器进行了特殊处理,省略掉了一个箭头* 保持了程序的可读性*/// 一般结构体的指针才会使用'->'来访问成员// 所以当迭代器管理的节点中的数据是结构体的时候,就可以用'->'cout << it->first << ", " << it->second << endl; // 常用这种写法it++;
}

请添加图片描述


7.3 map的查找操作

  1. find():如果找到具有指定键(key)的元素,则返回该元素的迭代器,否则返回map::end的迭代器

使用举例:

//统计单词出现的次数
//定义map,遍历str,向map中插入元素(键值对)string str[] = { "sort","sort", "tree","sort", "node", "tree","sort", "sort", };// 定义map
map<string, int> Map;// 遍历str
for (auto& e : str)  // 传引用,避免string深拷贝
{// 先查找判断当前单词是否已经在Map中了auto ret = Map.find(e);if (ret == Map.end()) // 如果不在Map中,返回Map中最后一个元素后面的迭代器{Map.insert(make_pair(e, 1)); // 插入pair对象(键值对),即<单词,单词出现次数>}else // 如果在Map中,返回该元素的迭代器{ret->second++; // 单词出现的次数+1}
}// 遍历map,这里的e是map的元素(即pair对象),打印<单词,单词出现次数>
for (auto& e : Map)
{cout << e.first << ", " << e.second << endl;
}

上述解法,先查找当前单词是否在map中,如果不在,则插入,但是在插入函数内又会查找一次,找到插入的位置,有点冗余

第二种解法,插入元素时,insert本来就有查找功能:

void test_map()
{string str[] = { "sort","sort", "tree","sort", "node", "tree","sort", "sort", };// 定义mapmap<string, int> count_map;// 遍历strfor (auto& e : str){// 插入元素auto ret = count_map.insert(make_pair(e, 1));// insert返回值类型是:pair<map<string, int>::iterator, bool>// 插入失败,说明该元素已存在于map中,函数返回一个pair对象// 即:pair<指向该元素的迭代器, false>if (ret.second == false){(ret.first)->second++; // 对当前元素的value值加1}}// 遍历map,这里的e是map的元素(即pair对象)for (auto& e : count_map){cout << e.first << ", " << e.second << endl;}
}

第三种解法:使用 map::operator[] 函数根据当前元素的键值key查找,判断该元素是否在 map中,如果在,返回其映射值value的引用,如果不在,当成新元素插入,并返回其映射值 value 的引用

string str[] = { "sort","sort", "tree","sort", "node", "tree","sort", "sort", };// 定义map
map<string, int> Map;// 使用operator[]函数
// 若元素e存在,返回其对应映射值value,并加1
// 若元素e不存在,则插入,返回其对应映射值value,并加1
for (auto& e : str)
{Map[e]++;
}// 遍历map,打印< 单词,单词出现次数 >
for (auto& e : Map)
{cout << e.first << ", " << e.second << endl;
}

请添加图片描述


8.map的总结

  1. map中的的元素是键值对(pair结构体)

  2. map中的key是唯一的,并且不能修改,只能修改key对应的映射值value

  3. 在map中,键值 key 通常用于排序和惟一地标识元素,键值 key 和值 value 的类型可能不同,在 map 的内部,key 与 value 通过成员类型 value_type 绑定在一起,为其取别名为 pair:

    typedef pair<const Key, T> value_type;
    
  4. 默认按照小于的方式对 key 进行比较

  5. map 中通过键值访问单个元素的速度通常比 unordered_map 容器慢,但 map 允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列

  6. map支持 [] 操作符,operator[] 中实际是进行查找插入,即在 [] 中放入 key,就可以找到与 key 对应的 value

  7. map的底层为平衡二叉搜索树(红黑树),查找效率比较高

  8. map不允许数据冗余,所以插入元素时,如果已存在相同key值的元素,则无法插入。可对一堆数据去重


9.STL库中multimap的官方介绍

multimap 的使用和 map 几乎一样,它们之间的区别就是:

  • map 是不允许数据冗余的,而 multimap 允许数据冗余,可以有多个相同 key 值的元素
  • multimap中没有重载 operator[] 操作符(有歧义,有多个相同 key,到底返回哪个 key 的映射值 value 不清楚)

http://chatgpt.dhexx.cn/article/rIJQcCqt.shtml

相关文章

STL库(1)

STL库&#xff08;1&#xff09; vectorvector介绍vector使用初始化元素访问内存扩容插入删除 listlist介绍初始化&#xff0c;元素访问插入删除元素 vector和list区别 vector vector介绍 vector是可以改变大小的数组的容器。其内存结构和数组一样&#xff0c;使用连续的存储…

【C++学习五】STL库的应用

文章目录 初识C之 STL标准库1. CSTL的三大核心组件2. 自定义函数与算法对容器实现操作3. 基于自定义函数以及操作模板实现简易数字图像处理3.1 图像灰度变换3.2 图像二值化 4. 初识STL容器之&#xff1a;set集合5.初识STL容器之&#xff1a;map(关联容器)结语 初识C之 STL标准库…

STL库:vector

STL库&#xff1a;vector 文章目录 STL库&#xff1a;vector1.STL库对vector的官方介绍2.vecotr的常用接口2.1 vector的构造函数2.2 vector的迭代器与遍历操作2.3 vector的容量操作2.4 vector的访问操作2.5 vector的修改操作 3.vector迭代器失效问题3.1 insert导致的迭代器失效…

深入理解STL库

关注本人公众号&#xff0c;获取更多学习资料&#xff01; 微信公众号搜索&#xff1a;阿Q正砖 上期说过C这块面试问的东西也蛮多&#xff0c;简历上只要出现C这几个字&#xff0c;那么STL库就是必问。 总不能是面试官问你了解STL库吗&#xff1f;你尴尬的说这块不怎么熟悉。…

C++ STL标准库

STL 组件 STL 是 C 标准程序库的核心。STL 内的所有组件都由模板构成&#xff0c;其元素可以是任意型别。程序员通过选用恰当的群集类别调用其成员函数和算法中的数据即可&#xff0c;但代价是 STL 晦涩难懂。 STL 组件主要包括容器&#xff0c;迭代器、算法和仿函数。 容器…

C++语法篇之STL库

1. STL介绍 STL是Standard Template Library的缩写&#xff0c;即标准模板库。之前在写 Templates 模板的时候&#xff0c;提到过STL对于模板的应用。STL是由多个模板类构成&#xff0c;能够为开发者提供通用的数据结构和算法。 STL主要包含以下内容&#xff1a; 容器 Conta…

【c++ • STL】初步认识什么是 STL 标准库

&#x1f680; 个人简介&#xff1a;CSDN「博客新星」TOP 10 &#xff0c; C/C 领域新星创作者&#x1f49f; 作 者&#xff1a;锡兰_CC ❣️&#x1f4dd; 专 栏&#xff1a;从零开始的 c 之旅&#x1f308; 若有帮助&#xff0c;还请关注➕点赞➕收藏&#xff0c;不行的…

STL库:list

STL库&#xff1a;list 文章目录 STL库&#xff1a;list1.STL库对list的官方介绍2.list的常用接口2.1 list的构造函数2.2 list的迭代器与遍历操作2.3 list的容量操作2.4 list的访问操作2.5 list的修改操作2.6 list的特别容器操作 3.list的底层源码4.list的模拟实现4.1 list的结…

STL库:string

STL库&#xff1a;string 文章目录 STL库&#xff1a;string1.STL库对于string类的介绍2.string常用接口的掌握2.1 string的构造接口2.2 string的容量操作接口2.3 string的访问操作接口2.4 string的迭代器遍历操作接口2.5 string的修改操作接口2.6 string的非成员函数重载接口2…

C++ 标准模板库STL

目录 前言 一、STL简介 二、STL的组件 三、STL头文件与命名空间 四、STL三大组件之 —— 容器 4.1 容器概述 4.2 序列式容器 4.3 排序式容器 4.4 哈希容器 五、STL三大组件之 —— 迭代器 5.1 迭代器概述 5.2 五种迭代器 5.3 迭代器的定义 5.4 迭…

C++ - STL标准库

1.C STL标准库简介 长久以来&#xff0c;软件界一直希望建立一种可重复利用的东西&#xff0c;以及一种得以制造出”可重复运用的东西” 的方法&#xff0c;从函数(functions)&#xff0c;类别(classes),函数库(function libraries),类别库(class libraries)、各种 组件&…

STL库--概述

C标准模板库&#xff08;Standard Template Library,STL&#xff09;是泛型程序设计最成功的实例。STL是一些常用数据结构和算法的模板的集合。 STL六大组件&#xff1a; 容器&#xff08;containers&#xff09;&#xff1a;存放数据 算法&#xff08;algorithms&#xff09;&…

Standard Template Library(STL,标准模板库)

Standard Template Library(STL&#xff0c;标准模板库) STL&#xff08;标准模板库&#xff09;是C标准程序库的核心&#xff0c;它深刻影响了标准程序库的整体结构。 STL是一个泛型(generic)程序库&#xff0c;提供一系列软件方案&#xff0c;利用先进&#xff0c;高效的算…

pyqt学习笔记

pyqt学习笔记 文章目录 pyqt学习笔记前言pyqt主要模块开发环境安装qtpython选择使用anaconda集成版本&#xff1a;anaconda的特点&#xff1a;安装步骤&#xff1a; pycharm导入anaconda:pycharm设置qtdesigner&#xff0c;ui转py工具: 前言 gui学习是一个比较重要的内容&…

[ PyQt入门教程 ] PyQt5开发环境搭建和配置

PyQt5工具可以快速实现简单的界面开发&#xff0c;包括界面设计、布局管理以及业务逻辑实现&#xff08;信号与槽&#xff09;。简单说就是使用PyQt5工具可以快速画一个控件摆放整齐、界面整洁有序、布局合理的界面。 课程目标 可以动手实现简单的GUI程序。系列文章主要以动手…

PyQt(QtDesigner+Python)编写程序的使用教程(简单版)

有同学问我具体怎么实现QtDesignerPython&#xff0c;简单写一下方便查看 1.安装好后Qtdesinger,打开软件&#xff0c;操作控件设计好想要的界面&#xff1b; 2.将Qtdesinger编写的.ui文件&#xff0c;使用PyUIC&#xff08;需要自己安装配置好&#xff09;软件转到.py文件 …

Python开发:PyQT安装教程

不管开发什么程序&#xff0c;一个友好的用户界面都是至关重要的&#xff0c;然而Python自身并没有集成GUI&#xff0c;但是好在自Python诞生之日起&#xff0c;就有许多优秀的GUI工具集被整合到Python当中&#xff0c;使得Python也可以在图形界面编程领域大展身手。所以从这一…

PyQt5学习教程

介绍 Qt&#xff08;官方发音 [kju:t]&#xff0c;音同 cute&#xff09;是一个跨平台的 C 开发库&#xff0c;主要用来开发图形用户界面&#xff08;Graphical User Interface&#xff0c;GUI&#xff09;程序&#xff0c;当然也可以开发不带界面的命令行&#xff08;Command…

PyQt完整入门教程 | 例程附代码

关注、星标公众号&#xff0c;直达精彩内容 来源&#xff1a;cnblogs 作者&#xff1a;lovesoo 1、GUI开发框架简介 pyqt是个好东西&#xff0c;可以做完整的测试方案、脚本、工具进行整合复用等等&#xff0c;本文将以一个实例和大家一起分享。先给自己挖个坑开个头&#xff0…

PyQt初级教程

PyQt5简介 这是一个PyQt5的入门教程.目的是帮助你使用PyQt5.本教程创建并在Linux上测试.PyQt4教程则覆盖了PyQt4,对应Python的2.x和3.x的Qt4的库. 原作地址&#xff1a;http://zetcode.com/gui/pyqt5/ 原翻译地址 &#xff1a;http://blog.csdn.net/neverstop_2009/article/c…