C++ STL精通之旅:向量、集合与映射等容器详解

简介: C++ STL精通之旅:向量、集合与映射等容器详解



STL

STL 作为一个封装良好,性能合格的 C++ 标准库,在算法竞赛中运用极其常见。灵活且正确使用 STL 可以节省非常多解题时间,这一点不仅是由于可以直接调用,还是因为它封装良好,可以让代码的可读性变高,解题思路更清晰,调试过程往往更顺利。

不过 STL 毕竟使用了很多复杂的结构来实现丰富的功能,它的效率往往是比不上自己手搓针对特定题目的数据结构与算法的。因此,STL 的使用相当于使用更长的运行时间换取更高的编程效率。因此,在实际比赛中要权衡 STL 的利弊,不过这一点就得靠经验了。

接下来,博主会分享在算法竞赛中常用的 STL 容器,对于算法,函数和迭代器,就不着重展开讲了。

C++ 标准模板库 (STL, Standard Template Library):包含一些常用数据结构与算法的模板的 C++ 软件库。其包含四个组件——算法 (Algorithms)、容器 (Containers)、仿函数 (Functors)、迭代器 (Iterators).

示例:

  • 算法(Algorithms):STL中的算法是一组对容器进行操作的函数,它们独立于任何特定的数据结构,可以用于执行各种任务,如搜索、排序、复制和修改容器中的元素。这些算法是泛型的,意味着它们可以用于不同类型和容器的数据,体现了泛型编程的思想。

  • 容器(Containers):容器是用来存储数据的对象,例如数组、队列、链表、集合等。STL提供了多种容器类型,每种都设计用于特定类型的数据访问和存储。容器管理对象的集合,并提供插入、删除和遍历元素等操作。

  • 仿函数(Functors):仿函数是重载了操作符()的类或类对象,它可以像函数一样被调用。在STL中,仿函数通常用作算法的参数,允许用户自定义算法的行为,使得算法更加灵活和可配置。

  • 迭代器(Iterators):迭代器是一种类似于指针的对象,用于在容器中遍历元素。每个容器都定义了相应的迭代器类型,迭代器提供了读取和修改容器元素的方法。迭代器分为输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器,不同类型的迭代器支持不同的操作。

常用容器

顺序容器

  • 向量vector

头文件:#include <vector>

连续的顺序的储存结构(和数组一样的类别),但是有长度可变的特性。

构造

vector<类型> arr(长度, [初值])

时间复杂度:O(n)

尾接 & 尾删
  • push_back(元素):在 vector 尾接一个元素,数组长度 +1.
  • pop_back():删除 vector 尾部的一个元素,数组长度 -1.

时间复杂度:均摊 O(1)

中括号运算符

和一般数组一样的作用

时间复杂度:O(1)

获取长度

.size()

获取当前 vector 的长度

时间复杂度:O(1)

清空

.clear()

清空 vector

时间复杂度:O(n)

判空

.empty()

如果是空返回 true 反之返回 false.

时间复杂度:O(1)

改变长度

.resize(新长度, [默认值])

修改 vector 的长度

  • 如果是缩短,则删除多余的值
  • 如果是扩大,且指定了默认值,则新元素均为默认值(旧元素不变)

时间复杂度:O(n)

提前分配好空间

代码演示

运行结果

关联容器

  • 集合set

头文件#include <set>

提供对数时间的插入、删除、查找的集合数据结构。底层原理是红黑树。

集合三要素 解释 set multiset unordered_set
确定性 一个元素要么在集合中,要么不在
互异性 一个元素仅可以在集合中出现一次 ❌(任意次)
无序性 集合中的元素是没有顺序的 ❌(从小到大) ❌(从小到大)
构造

set<类型, 比较器> st

  • 类型:要储存的数据类型
  • 比较器:比较大小使用的比较器,默认为 less<类型>,可自定义

对于需要自定义比较器的情况,涉及一些初学时容易看迷糊的语法(重载小括号运算符 / lambda 表达式),在此就不展开讲了。

遍历

其他
作用 用法 示例
插入元素 .insert(元素) st.insert(1);
删除元素 .erase(元素) st.erase(2);
查找元素 .find(元素) auto it = st.find(1);
判断元素是否存在 .count(元素) st.count(3);
查看大小 / 清空 / 判空

增删查时间复杂度均为 O(\log n)

代码演示

运行结果

  • 映射map

头文件#include <map>

提供对数时间的有序键值对结构。底层原理是红黑树。

映射:                                        

                                                                 

性质 解释 map multimap unordered_map
互异性 一个键仅可以在映射中出现一次 ❌(任意次)
无序性 键是没有顺序的 ❌(从小到大) ❌(从小到大)
常用方法
构造

map<键类型, 值类型, 比较器> mp

  • 键类型:要储存键的数据类型
  • 值类型:要储存值的数据类型
  • 比较器:键比较大小使用的比较器,默认为 less<类型>,可自定义
遍历

其他
作用 用法 示例
增 / 改 / 查元素 中括号 mp[1] = 2;
查元素(返回迭代器) .find(元素) auto it = mp.find(1);
删除元素 .erase(元素) mp.erase(2);
判断元素是否存在 .count(元素) mp.count(3);
查看大小 / 清空 / 判空

增删改查时间复杂度均为 O(\log n)

代码演示1
运行结果1

代码演示2

 运行结果2

string map
代码演示3

运行结果3

mp没赋初值,默认为0
代码演示4

运行结果4

容器适配器

  • 栈stack

头文件#include <stack>

通过二次封装双端队列 (deque) 容器,实现先进后出的栈数据结构。

常用方法
作用 用法 示例
构造 stack<类型> stk stack<int> stk;
进栈 .push(元素) stk.push(1);
出栈 .pop() stk.pop();
取栈顶 .top() int a = stk.top();
查看大小 / 清空 / 判空
代码演示1

运行结果1

vector也可以当栈来用
代码演示2

运行结果2

  • 队列queue

头文件#include <queue>

通过二次封装双端队列 (deque) 容器,实现先进先出的队列数据结构。

常用方法
作用 用法 示例
构造 queue<类型> que queue<int> que;
进队 .push(元素) que.push(1);
出队 .pop() que.pop();
取队首 .front() int a = que.front();
取队尾 .back() int a = que.back();
查看大小 / 清空 / 判空
代码演示

运行结果

  • 优先队列priority_queue

头文件#include <queue>

提供常数时间的最大元素查找,对数时间的插入与提取,底层原理是二叉堆。

常用方法
构造

priority_queue<类型, 容器, 比较器> pque

  • 类型:要储存的数据类型
  • 容器:储存数据的底层容器,默认为 vector<类型>,竞赛中保持默认即可
  • 比较器:比较大小使用的比较器,默认为 less<类型>,可自定义
priority_queue<int> pque1;                            // 储存int的大顶堆
priority_queue<int, vector<int>, greater<int>> pque2; // 储存int的小顶堆
其他
作用 用法 示例
进堆 .push(元素) que.push(1);
出堆 .pop() que.pop();
取堆顶 .top() int a = que.top();
查看大小 / 判空

进出队复杂度 O(\log n),取堆顶 $O(1).

大顶堆
代码演示1

运行结果1

小顶堆
代码演示2

运行结果2

修改堆顶元素
代码演示3

运行结果3

字符串

  • string (basic_string<char>)

头文件#include <string>

顾名思义,就是储存字符串的。

常用方法
构造

输入输出

C++

C

其他
作用 用法 示例
修改、查询指定下标字符 [] s[1] = 'a';
是否相同 == if (s1 == s2) ...
字符串连接 + string s = s1 + s2;
尾接字符串 += s += "awa";
取子串 .substr(起始下标, 子串长度) string sub = s.substr(2, 10);
查找字符串 .find(字符串, 起始下标) int pos = s.find("awa");
数值与字符串互转(C++11)
目的 函数
int / long long / float / double / long double string to_string()
string int stoi()
string long long stoll()
string float stof()
string double stod()
string long double stold()
尾接字符串一定要用 +=

代码演示

运行结果

对与元组

  • 二元组pair

头文件#include <utility>

顾名思义,就是储存二元组的。

常用方法
构造

pair<第一个值类型, 第二个值类型> pr

  • 第一个值类型:要储存的第一个值的数据类型
  • 第二个值类型:要储存的第二个值的数据类型

赋值

老式

列表构造 C++11

取值

直接取值

  • 取第一个值:.first
  • 取第二个值:.second

结构化绑定 C++17

判同

直接用 == 运算符

适用场景

所有需要二元组的场景均可使用,效率和自己定义结构体差不多。

代码演示

运行结果

希望对你有帮助!加油!

若您认为本文内容有益,请不吝赐予赞同并订阅,以便持续接收有价值的信息。衷心感谢您的关注和支持!

目录
相关文章
|
7月前
|
缓存 算法 程序员
C++STL底层原理:探秘标准模板库的内部机制
🌟蒋星熠Jaxonic带你深入STL底层:从容器内存管理到红黑树、哈希表,剖析迭代器、算法与分配器核心机制,揭秘C++标准库的高效设计哲学与性能优化实践。
C++STL底层原理:探秘标准模板库的内部机制
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
363 2
|
存储 算法 C++
【c++丨STL】map/multimap的使用
本文详细介绍了STL关联式容器中的`map`和`multimap`的使用方法。`map`基于红黑树实现,内部元素按键自动升序排列,存储键值对,支持通过键访问或修改值;而`multimap`允许存在重复键。文章从构造函数、迭代器、容量接口、元素访问接口、增删操作到其他操作接口全面解析了`map`的功能,并通过实例演示了如何用`map`统计字符串数组中各元素的出现次数。最后对比了`map`与`set`的区别,强调了`map`在处理键值关系时的优势。
732 73
|
存储 算法 C++
【c++丨STL】set/multiset的使用
本文深入解析了STL中的`set`和`multiset`容器,二者均为关联式容器,底层基于红黑树实现。`set`支持唯一性元素存储并自动排序,适用于高效查找场景;`multiset`允许重复元素。两者均具备O(logN)的插入、删除与查找复杂度。文章详细介绍了构造函数、迭代器、容量接口、增删操作(如`insert`、`erase`)、查找统计(如`find`、`count`)及`multiset`特有的区间操作(如`lower_bound`、`upper_bound`、`equal_range`)。最后预告了`map`容器的学习,其作为键值对存储的关联式容器,同样基于红黑树,具有高效操作特性。
614 3
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
494 12
|
11月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
264 0
|
11月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
421 0
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
252 16

热门文章

最新文章