普及组常用STL
STL简介
在OI信息学竞赛中,STL(Standard Template Library,标准模板库)是一个强大且实用的工具,能显著提升编程效率。
STL 是 C++ 标准库的重要组成部分,由惠普实验室开发,于 1998 年被纳入 C++ 标准。它运用模板技术,实现了数据结构和算法的泛型化,使代码具备高度的可复用性和灵活性。
STL 主要包含容器、算法和迭代器三大部分。
- 容器:用于存储和管理数据,提供了多种数据结构。
- 算法:提供了一系列通用算法,如排序、查找、替换、合并等。这些算法可以与各种容器配合使用,无需考虑容器的具体类型,大大提高了代码的编写效率。
- 迭代器:作为容器和算法之间的桥梁,迭代器提供了一种统一的方式来访问容器中的元素。它类似于指针,但具有更高的抽象性和安全性。通过迭代器,算法可以在不了解容器内部实现的情况下对容器元素进行操作。
在竞赛中,时间紧迫,使用 STL 可以快速实现常见的数据结构和算法,减少代码编写时间,让选手能够将更多精力放在问题的解决思路上。
vector
简介与概述、功能介绍
vector
是C++标准模板库(STL)里的动态数组容器。和普通数组不同,vector
能够在运行时动态调整大小。它支持随机访问,意味着可以像操作普通数组那样通过下标快速访问元素。同时,还能方便地在末尾添加或删除元素。
适用场景
- 数据数量不确定时:当你不清楚要存储的数据量,或者数据量会动态变化,
vector
能根据需求自动调整大小。 - 需要随机访问元素:若要频繁地通过下标访问元素,
vector
提供了高效的随机访问能力。 - 替代普通数组:可以避免手动管理内存,减少因内存管理不当引发的错误。
原理和使用
vector
内部借助动态数组来实现。当元素数量超出当前容量时,会重新分配更大的内存空间,再把原有的元素复制到新空间里。常用操作及其时间复杂度如下:
push_back()
:在末尾添加元素,平均时间复杂度为 ,但在需要重新分配内存时为 。pop_back()
:删除末尾元素,时间复杂度为 。size()
:获取元素数量,时间复杂度为 。[]
或at()
:随机访问元素,时间复杂度为 。
经典例题及代码实现
题面描述
输入 个整数,将它们存储在 vector
中,然后逆序输出这些整数。
输入输出样例
- 输入:
第一行的 5
表示整数的个数,第二行是这 5 个整数。
- 输出:
代码实现
总结
vector
是OI竞赛中非常实用的容器,它结合了数组的随机访问特性和动态调整大小的能力。在数据量不确定或者需要随机访问元素的场景下,vector
是很好的选择。不过,要注意 push_back()
可能导致的内存重新分配问题,这会带来额外的时间开销。
stack
简介与概述、功能介绍
stack
是遵循后进先出(LIFO,Last In First Out)原则的数据结构。它只允许在栈顶进行插入(入栈,push
)和删除(出栈,pop
)操作,还能查看栈顶元素(top
)。
适用场景
- 括号匹配问题:通过栈来检查括号是否成对出现,遇到左括号入栈,遇到右括号时检查栈顶元素是否为对应的左括号。
- 递归模拟:将递归过程转化为栈的操作,避免递归深度过大导致栈溢出。
- 表达式求值:在处理后缀表达式求值等问题时发挥作用。
原理和使用
stack
基于其他容器(如 vector
、deque
等)实现,默认使用 deque
。它只暴露栈顶元素,通过 push()
将元素压入栈顶,pop()
移除栈顶元素,top()
获取栈顶元素。这些操作的时间复杂度均为 。
经典例题及代码实现
题面描述
给定一个只包含 (
和 )
的字符串,判断括号是否匹配。
输入输出样例
- 输入:
- 输出:
代码实现
总结
stack
的后进先出特性使其在处理具有嵌套或逆序逻辑的问题时非常高效。在括号匹配、递归模拟等场景中,stack
是不可或缺的工具。使用时要注意栈为空的情况,避免出现访问空栈的错误。
queue
简介与概述、功能介绍
queue
是遵循先进先出(FIFO,First In First Out)原则的数据结构。元素从队列尾部插入(入队,push
),从队列头部删除(出队,pop
),还能查看队头元素(front
)和队尾元素(back
)。
适用场景
- 广度优先搜索(BFS):在BFS算法中,队列用于存储待访问的节点,保证节点按照层次顺序被访问。
- 任务调度:按照任务到达的顺序依次处理任务,例如操作系统中的任务队列。
原理和使用
queue
通常基于 deque
实现。通过 push()
在队尾插入元素,pop()
删除队头元素,front()
获取队头元素,back()
获取队尾元素。这些操作的时间复杂度均为 。
经典例题及代码实现
题面描述
在一个 的迷宫中,从起点 走到终点 ,每次只能向上下左右四个方向移动一步,求最短路径长度。迷宫中 0
表示可以通行,1
表示障碍物。
输入输出样例
- 输入:
第一行的 3
和 3
表示迷宫的行数和列数,接下来三行是迷宫的布局,最后两行分别是起点和终点的坐标。
- 输出:
代码实现
总结
queue
的先进先出特性使其在广度优先搜索和任务调度等场景中非常有用。在BFS中,队列确保了节点按照层次顺序被访问,从而能找到最短路径。使用时要注意队列的初始化和判空操作。
list
简介与概述、功能介绍
list
是一种双向链表容器,它支持在任意位置高效地插入和删除元素。与 vector
不同,list
不支持随机访问,访问元素需要从头或尾开始遍历。
适用场景
- 频繁插入和删除操作:当需要在容器中间频繁插入或删除元素时,
list
的效率比vector
高,因为链表的插入和删除操作只需要修改指针。 - 实现双向链表相关算法:可以利用
list
的双向链表特性实现一些特定的算法。
原理和使用
list
使用双向链表实现,每个节点包含指向前一个节点和后一个节点的指针。插入和删除操作只需要修改指针,时间复杂度为 。但访问元素需要从头或尾开始遍历,时间复杂度为 。常用操作有 push_back()
(在末尾插入元素)、push_front()
(在头部插入元素)、erase()
(删除指定位置的元素)等。
经典例题及代码实现
题面描述
有一个整数序列,需要在指定位置插入一个新的整数,然后输出序列。
输入输出样例
- 输入:
第一行的 5
表示序列的长度,第二行是序列的元素,第三行的 3
表示插入位置,10
表示要插入的整数。
- 输出:
代码实现
总结
list
在需要频繁进行插入和删除操作的场景中表现出色。但由于不支持随机访问,在需要随机访问元素的场景中效率较低。使用 list
时,要注意迭代器的使用,避免迭代器失效的问题。
priority_queue
简介与概述、功能介绍
priority_queue
是一种优先队列,它会根据元素的优先级对元素进行排序。默认情况下,最大的元素总是位于队列的顶部。可以通过自定义比较函数来改变优先级规则。
适用场景
- 求最大或最小元素:例如在 Dijkstra 算法中,用于选择距离最小的节点。
- 任务调度:根据任务的优先级进行处理,优先级高的任务先被处理。
原理和使用
priority_queue
通常使用堆(如大顶堆或小顶堆)实现。插入元素时,会将元素插入到堆中并调整堆的结构;删除元素时,会删除堆顶元素并重新调整堆。插入和删除操作的时间复杂度均为 ,获取堆顶元素的时间复杂度为 。
经典例题及代码实现
题面描述
给定 个整数,每次取出最大的数,将其减 1 后放回队列,重复 次,最后输出队列中所有元素的和。
输入输出样例
- 输入:
第一行的 5
表示整数的个数,3
表示操作次数,第二行是这 5 个整数。
- 输出:
代码实现
总结
priority_queue
在需要动态维护最大或最小元素的场景中非常有用。通过堆的实现,它能高效地完成插入、删除和获取最大(小)元素的操作。使用时要注意默认是大顶堆,如果需要小顶堆,可以自定义比较函数。