Skip to content

STL模板

约 4177 字大约 14 分钟

2025-06-25

常用函数与算法模板:min、max、swap、sort

常用函数与算法模板

在C++信奥赛中,STL(标准模板库)提供的minmaxswapsort是最常用的工具,它们能大幅简化代码、提高效率。下面详细讲解这些函数的用法及实战模板。

一、minmax:取最小值与最大值

minmax:取最小值与最大值

minmax用于获取两个或多个元素中的最小值和最大值,定义在<algorithm>头文件中。

1. 基本用法(两个元素)

c++

2. 多个元素的最值(initializer_list

C++11起支持传入初始化列表(用{}包裹)求多个元素的最值:

c++
int main() {
    int m = min({1, 5, 2, 9, 3});  // 多个整数的最小值
    int M = max({1, 5, 2, 9, 3});  // 多个整数的最大值
    cout << m << " " << M;  // 输出1 9
    return 0;
}

3. 自定义比较(结构体/对象)

对结构体或自定义类型,需指定比较规则(通过lambda或函数):

c++

二、swap:交换两个元素的值

swap:交换两个元素的值

swap用于交换两个同类型变量的值,定义在<algorithm>中,无需手动实现临时变量。

1. 基本用法

c++

2. 交换数组元素或结构体

c++

三、sort:排序算法(核心)

sort:排序算法(核心)

sort是信奥赛中最常用的排序函数,基于快速排序的优化版本(平均时间复杂度O(n log n)),定义在<algorithm>中。

1. 基本用法(默认升序)

c++

2. 降序排序(自定义比较)

通过greater<类型>()或lambda表达式实现降序:

c++

3. 排序结构体/自定义类型

必须指定比较规则(按结构体成员排序):

c++

4. 部分排序(指定范围)

可只排序数组的前k个元素或中间一段:

c++

四、信奥赛实战模板

信奥赛实战模板

1. 数组排序模板

c++

2. 结构体排序模板(按多关键字)

c++

3. 查找第k小元素(利用sort)

c++
// 查找数组中第k小的元素(k从1开始)
int findKthSmallest(int arr[], int n, int k) {
    sort(arr, arr + n);  // 升序排序
    return arr[k - 1];   // 第k小元素在索引k-1
}

五、避坑指南

避坑指南

  1. sort的范围是左闭右开
    sort(begin, end)排序的是[begin, end)区间,即包含begin指向的元素,不包含end指向的元素:

    c++
    int arr[5] = {3,1,4,1,5};
    sort(arr, arr + 3);  // 只排序前3个元素(索引0,1,2)
  2. 自定义比较函数的返回值
    比较函数cmp(a,b)返回true表示a应排在b前面,需确保逻辑正确(避免矛盾):

    c++
    // 错误:可能导致排序异常
    bool badCmp(int a, int b) {
        return a >= b;  // 存在a==b时返回true,违反严格弱序
    }
  3. min/max的参数类型需一致
    不能比较不同类型的元素(如intdouble需显式转换):

    c++
    int a = 3;
    double b = 2.5;
    // min(a, b);  // 错误:类型不一致
    min((double)a, b);  // 正确:转换为同一类型
  4. swap对容器的效率
    swap两个容器(如vector)时,内部仅交换指针,效率极高(无需复制元素):

    c++
    vector<int> v1(1000000), v2;
    swap(v1, v2);  // 瞬间完成,不会复制百万元素

重要

  • 实战中需重点掌握sort的自定义排序(尤其是结构体多关键字排序),这是解决复杂排序问题的核心。同时注意函数的参数范围和类型匹配,避免常见错误。

  • STL的minmaxswapsort是信奥赛的“利器”,掌握它们能:

    • 减少重复代码(无需手动实现排序、交换等逻辑)。
    • 保证算法效率(sort的性能接近最优)。
    • 提升代码可读性(函数名直观,逻辑清晰)。

栈(stack)、队列(queue)、链表(list)、向量(vector)等容器

容器

在C++信奥赛中,STL(标准模板库)提供的容器是处理数据的核心工具。栈(stack)、队列(queue)、链表(list)、向量(vector)是最常用的四大容器,它们各有特性,适用于不同场景。

一、向量(vector):动态数组(最常用)

向量(vector):动态数组(最常用)

vector动态数组,支持随机访问,大小可自动调整,是信奥赛中使用频率最高的容器。其底层是连续内存空间,兼顾数组的高效访问和动态扩展能力。

1. 核心特性

  • 随机访问:通过下标[]at()访问元素,时间复杂度O(1)
  • 动态扩容:当元素数量超过当前容量时,自动分配更大的内存(通常是原容量的2倍)。
  • 尾部操作高效:在末尾插入(push_back)或删除(pop_back)元素,时间复杂度O(1)
  • 中间操作低效:在中间插入/删除元素需移动后续元素,时间复杂度O(n)

2. 头文件与基本用法

c++

3. 信奥赛应用场景

  • 存储动态大小的数组(如输入数据量未知时)。
  • 需要随机访问元素的场景(如模拟数组、存储坐标等)。
  • 作为其他算法的基础容器(如排序、查找)。

示例:存储并排序未知数量的整数

c++
vector<int> nums;
int x;
while (cin >> x) {  // 读入未知数量的整数
    nums.push_back(x);
}
sort(nums.begin(), nums.end());  // 排序

二、栈(stack):后进先出(LIFO)

栈(stack):后进先出(LIFO)

stack后进先出(Last In First Out) 的容器,仅允许在顶部(栈顶)进行插入和删除操作,类似“叠盘子”。

1. 核心特性

  • 操作受限:只能访问栈顶元素,不能遍历或随机访问中间元素。
  • 高效操作:入栈(push)、出栈(pop)、访问栈顶(top)均为O(1)

2. 头文件与基本用法

c++

3. 信奥赛应用场景

  • 括号匹配问题:用栈存储左括号,遇到右括号时弹出栈顶检查匹配。
  • 深度优先搜索(DFS):手动模拟递归(避免递归栈溢出)。
  • 表达式求值:如后缀表达式计算、中缀转后缀。
  • 单调栈问题:求Next Greater Element等。

示例:括号匹配检查

c++

三、队列(queue):先进先出(FIFO)

队列(queue):先进先出(FIFO)

queue先进先出(First In First Out) 的容器,仅允许在队尾插入、队头删除,类似“排队”。

1. 核心特性

  • 操作受限:只能访问队头和队尾元素,不能遍历或随机访问。
  • 高效操作:入队(push)、出队(pop)、访问队头(front)、队尾(back)均为O(1)

2. 头文件与基本用法

c++

3. 信奥赛应用场景

  • 广度优先搜索(BFS):层次遍历(如二叉树层序遍历、最短路径问题)。
  • 模拟排队问题:如银行排队、打印机队列等。
  • 滑动窗口:维护窗口内的元素(结合其他容器)。

示例:BFS求无权图的最短路径

c++

四、链表(list):双向链表

链表(list):双向链表

list双向链表,每个元素独立存储,通过指针连接,支持高效的插入和删除操作。

1. 核心特性

  • 非连续内存:元素在内存中不连续,通过指针连接。
  • 插入删除高效:在任意位置插入/删除元素,时间复杂度O(1)(已知位置时)。
  • 随机访问低效:访问第i个元素需从头遍历,时间复杂度O(n)
  • 双向遍历:可从头部或尾部开始遍历。

2. 头文件与基本用法

c++

3. 信奥赛应用场景

  • 频繁在中间插入/删除元素:如模拟链表操作、实现复杂数据结构(如邻接表)。
  • 需要双向遍历:如某些约瑟夫环问题、双向队列场景(但更推荐deque)。

注意:信奥赛中list使用频率低于vector,因为大多数场景需要随机访问,而list的遍历效率较低。

五、容器对比与选择指南

容器随机访问尾部插入/删除中间插入/删除遍历效率适用场景
vectorO(1)O(1)O(n)动态数组、随机访问、排序查找
stack不支持不支持(仅栈顶)不支持不支持遍历括号匹配、DFS、单调栈
queue不支持不支持(仅队尾入、队头出)不支持不支持遍历BFS、排队模拟
listO(n)O(1)O(1)频繁中间插入/删除、双向遍历

六、避坑指南

避坑指南

  1. vector的效率优化

    • 已知大致大小时,用reserve(n)预留容量,避免多次扩容:
    c++
    vector<int> v;
    v.reserve(100000);  // 预留10万个元素的空间
    • 清空元素用clear()(仅销毁元素,不释放容量),释放容量用swap
    c++
    vector<int>().swap(v);  // 交换临时对象,释放v的容量
  2. stack/queue的遍历限制
    这两个容器没有迭代器,不能直接遍历所有元素。若需遍历,可先复制到vector再操作:

    c++
    stack<int> st;
    // ... 入栈操作 ...
    vector<int> temp;
    while (!st.empty()) {
        temp.push_back(st.top());
        st.pop();
    }
    // 此时temp中存储栈的元素(逆序)
  3. 避免滥用list
    除非必须频繁在中间插入删除,否则优先用vector(随机访问和遍历效率更高)。

重要

  • 熟练掌握这些容器的特性和操作,能轻松应对信奥赛中大多数数据处理问题。
  • STL容器是信奥赛的“瑞士军刀”,选择合适的容器能大幅简化代码并提升效率:
    • 需随机访问或动态数组:选vector
    • 后进先出场景(如DFS、括号匹配):选stack
    • 先进先出场景(如BFS、排队):选queue
    • 频繁中间插入删除:选list