STL算法库讲解1

1. 迭代算法:for_each

核心特性

  • 最基础的遍历算法 ,对区间 [first, last) 中的每个元素执行指定操作
  • 非修改性算法(除非操作函数显式修改元素)
  • 支持自定义操作(函数指针、函数对象、Lambda 表达式)
  • 返回值:C++11 后返回传入的操作函数对象

函数原型

cpp 复制代码
template<class InputIt, class UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f);

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 1. 普通函数作为操作
    auto print = [](int x) { std::cout << x << " "; };
    std::for_each(vec.begin(), vec.end(), print); // 输出:1 2 3 4 5
    std::cout << std::endl;

    // 2. 修改元素(通过引用捕获)
    std::for_each(vec.begin(), vec.end(), [](int& x) { x *= 2; });
    // 现在vec:{2, 4, 6, 8, 10}

    // 3. 捕获外部变量
    int sum = 0;
    std::for_each(vec.begin(), vec.end(), [&sum](int x) { sum += x; });
    std::cout << "总和:" << sum << std::endl; // 输出:30

    return 0;
}

注意事项

  • 与 C++11 范围 for 循环的区别:for_each 可以返回操作函数对象,适合需要累积状态的场景
  • 操作函数的参数如果是值传递,无法修改原元素;必须使用引用传递 int& x
  • 时间复杂度:O (n),遍历一次区间

2. 查找算法

核心特性

  • 在区间中查找单个元素满足条件的元素
  • 返回值:找到则返回指向该元素的迭代器;未找到则返回 last 迭代器
  • 适用于无序区间(有序区间优先使用二分查找,效率更高)

常用函数

函数 功能
find(first, last, value) 查找第一个等于 value 的元素
find_if(first, last, pred) 查找第一个满足谓词 pred 的元素
find_if_not(first, last, pred) 查找第一个不满足谓词 pred 的元素(C++11)
adjacent_find(first, last) 查找第一对相邻且相等的元素
find_first_of(first1, last1, first2, last2) 查找区间 1 中第一个出现在区间 2 中的元素

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 3, 5, 3, 7, 9, 3};

    // 1. 查找指定值
    auto it1 = std::find(vec.begin(), vec.end(), 3);
    if (it1 != vec.end()) {
        std::cout << "找到3,位置:" << it1 - vec.begin() << std::endl; // 输出:1
    }

    // 2. 查找第一个大于5的元素
    auto it2 = std::find_if(vec.begin(), vec.end(), [](int x) { return x > 5; });
    std::cout << "第一个大于5的元素:" << *it2 << std::endl; // 输出:7

    // 3. 查找第一对相邻相等的元素
    std::vector<int> vec2 = {1, 2, 2, 3, 3, 3};
    auto it3 = std::adjacent_find(vec2.begin(), vec2.end());
    std::cout << "第一对相邻相等的元素:" << *it3 << std::endl; // 输出:2

    return 0;
}

3. 搜索算法

核心特性

  • 在区间中查找子序列连续重复元素
  • 与查找算法的区别:查找单个元素 vs 查找多个元素组成的序列
  • 返回值:找到则返回子序列起始位置的迭代器;未找到则返回 last

常用函数

函数 功能
search(first1, last1, first2, last2) 查找区间 1 中第一个出现的区间 2 子序列
find_end(first1, last1, first2, last2) 查找区间 1 中最后一个出现的区间 2 子序列
search_n(first, last, count, value) 查找连续 count 个等于 value 的元素

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> text = {1, 2, 3, 4, 2, 3, 4, 5};
    std::vector<int> pattern = {2, 3, 4};

    // 1. 查找第一个子序列
    auto it1 = std::search(text.begin(), text.end(), pattern.begin(), pattern.end());
    if (it1 != text.end()) {
        std::cout << "第一个子序列起始位置:" << it1 - text.begin() << std::endl; // 输出:1
    }

    // 2. 查找最后一个子序列
    auto it2 = std::find_end(text.begin(), text.end(), pattern.begin(), pattern.end());
    std::cout << "最后一个子序列起始位置:" << it2 - text.begin() << std::endl; // 输出:4

    // 3. 查找连续3个5
    std::vector<int> vec = {1, 5, 5, 5, 2, 5};
    auto it3 = std::search_n(vec.begin(), vec.end(), 3, 5);
    if (it3 != vec.end()) {
        std::cout << "找到连续3个5,起始位置:" << it3 - vec.begin() << std::endl; // 输出:1
    }

    return 0;
}

4. 统计算法

核心特性

  • 统计区间中满足条件的元素个数或进行数值累积
  • 分为两类:计数类(<algorithm>)和数值累积类(<numeric>

常用函数

头文件 函数 功能
<algorithm> count(first, last, value) 统计等于 value 的元素个数
<algorithm> count_if(first, last, pred) 统计满足谓词 pred 的元素个数
<numeric> accumulate(first, last, init) 计算区间元素与初始值 init 的和
<numeric> accumulate(first, last, init, op) 使用自定义操作 op 进行累积

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5, 3, 3};

    // 1. 统计等于3的元素个数
    int cnt1 = std::count(vec.begin(), vec.end(), 3);
    std::cout << "3的个数:" << cnt1 << std::endl; // 输出:3

    // 2. 统计偶数个数
    int cnt2 = std::count_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; });
    std::cout << "偶数个数:" << cnt2 << std::endl; // 输出:2

    // 3. 计算总和
    int sum = std::accumulate(vec.begin(), vec.end(), 0);
    std::cout << "总和:" << sum << std::endl; // 输出:21

    // 4. 计算乘积
    int product = std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>());
    std::cout << "乘积:" << product << std::endl; // 输出:540

    return 0;
}

5. 复制或变换算法

核心特性

  • 将源区间的元素复制变换后复制到目标区间
  • 要求目标区间有足够的空间 ,否则使用 back_inserter 等插入迭代器
  • 变换算法可以对每个元素执行自定义操作

常用函数

函数 功能
copy(first, last, d_first) 将区间 [first, last) 复制到以 d_first 开头的目标区间
copy_if(first, last, d_first, pred) 只复制满足谓词 pred 的元素(C++11)
copy_n(first, n, d_first) 复制前 n 个元素(C++11)
transform(first, last, d_first, unary_op) 对每个元素执行一元操作 unary_op 后复制
transform(first1, last1, first2, d_first, binary_op) 对两个区间的元素执行二元操作后复制

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator> // 用于back_inserter

int main() {
    std::vector<int> src = {1, 2, 3, 4, 5};
    std::vector<int> dest;

    // 1. 复制所有元素(使用back_inserter自动扩容)
    std::copy(src.begin(), src.end(), std::back_inserter(dest));
    // dest:{1, 2, 3, 4, 5}

    // 2. 复制偶数元素
    std::vector<int> even;
    std::copy_if(src.begin(), src.end(), std::back_inserter(even),
                 [](int x) { return x % 2 == 0; });
    // even:{2, 4}

    // 3. 元素平方变换
    std::vector<int> squared;
    std::transform(src.begin(), src.end(), std::back_inserter(squared),
                   [](int x) { return x * x; });
    // squared:{1, 4, 9, 16, 25}

    // 4. 两个区间元素相加
    std::vector<int> a = {1, 2, 3};
    std::vector<int> b = {4, 5, 6};
    std::vector<int> c;
    std::transform(a.begin(), a.end(), b.begin(), std::back_inserter(c),
                   std::plus<int>());
    // c:{5, 7, 9}

    return 0;
}

6. 填充算法

核心特性

  • 用指定值或生成的值填充区间
  • 分为两类:固定值填充和生成值填充

常用函数

函数 功能
fill(first, last, value) value 填充区间 [first, last)
fill_n(first, n, value) value 填充前 n 个元素
generate(first, last, gen) 用生成函数 gen 的返回值填充区间
generate_n(first, n, gen) 用生成函数 gen 的返回值填充前 n 个元素

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>

int main() {
    std::vector<int> vec(5);

    // 1. 填充固定值
    std::fill(vec.begin(), vec.end(), 10);
    // vec:{10, 10, 10, 10, 10}

    // 2. 填充前3个元素为0
    std::fill_n(vec.begin(), 3, 0);
    // vec:{0, 0, 0, 10, 10}

    // 3. 生成随机数填充
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(1, 100);
    std::generate(vec.begin(), vec.end(), [&]() { return dis(gen); });
    // 示例输出:{42, 17, 89, 3, 56}

    return 0;
}

7. 删除算法

⚠️ 核心注意事项

STL 删除算法不会真正删除容器元素 ,只是将需要保留的元素移到区间前部 ,返回新的尾迭代器。必须配合容器的 erase 方法才能真正释放内存。

常用函数

函数 功能
remove(first, last, value) 移除所有等于 value 的元素
remove_if(first, last, pred) 移除所有满足谓词 pred 的元素
unique(first, last) 移除相邻重复的元素(需先排序)
unique(first, last, pred) 使用自定义谓词判断重复

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 3, 2, 3, 4, 3, 5};

    // 1. 删除所有等于3的元素
    auto new_end1 = std::remove(vec.begin(), vec.end(), 3);
    // 此时vec:{1, 2, 4, 5, ?, ?, ?}(?为未定义值)
    vec.erase(new_end1, vec.end()); // 真正删除
    // vec:{1, 2, 4, 5}

    // 2. 删除所有偶数
    std::vector<int> vec2 = {1, 2, 3, 4, 5, 6};
    auto new_end2 = std::remove_if(vec2.begin(), vec2.end(),
                                   [](int x) { return x % 2 == 0; });
    vec2.erase(new_end2, vec2.end());
    // vec2:{1, 3, 5}

    // 3. 去重(必须先排序)
    std::vector<int> vec3 = {1, 2, 2, 3, 3, 3, 4};
    std::sort(vec3.begin(), vec3.end()); // 先排序
    auto new_end3 = std::unique(vec3.begin(), vec3.end());
    vec3.erase(new_end3, vec3.end());
    // vec3:{1, 2, 3, 4}

    return 0;
}

8. 排序算法

核心特性

  • STL 提供了多种排序算法,适用于不同场景
  • 默认使用 < 运算符比较,支持自定义比较函数
  • 时间复杂度:O (n log n)(主流排序算法)

常用函数

函数 功能 时间复杂度 稳定性
sort(first, last) 对区间进行快速排序(不稳定) O(n log n) 不稳定
stable_sort(first, last) 对区间进行归并排序(稳定) O(n log n) 稳定
partial_sort(first, middle, last) 对前 middle-first 个元素排序 O (n log k)(k 为排序元素个数) 不稳定
nth_element(first, nth, last) 将第 n 个元素放到正确位置,左边都小于它,右边都大于它 O(n) 不稳定

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {5, 2, 9, 1, 5, 6};

    // 1. 默认升序排序
    std::sort(vec.begin(), vec.end());
    // vec:{1, 2, 5, 5, 6, 9}

    // 2. 自定义降序排序
    std::sort(vec.begin(), vec.end(), std::greater<int>());
    // vec:{9, 6, 5, 5, 2, 1}

    // 3. 部分排序(前3个元素有序)
    std::vector<int> vec2 = {5, 2, 9, 1, 5, 6};
    std::partial_sort(vec2.begin(), vec2.begin() + 3, vec2.end());
    // vec2:{1, 2, 5, 9, 5, 6}(前3个最小的元素有序)

    // 4. 找第3小的元素(索引从0开始)
    std::vector<int> vec3 = {5, 2, 9, 1, 5, 6};
    std::nth_element(vec3.begin(), vec3.begin() + 2, vec3.end());
    std::cout << "第3小的元素:" << vec3[2] << std::endl; // 输出:5

    return 0;
}

9. 堆操作

核心特性

  • STL 实现了大顶堆(默认),即堆顶元素是最大值
  • 堆是一种完全二叉树,存储在数组中
  • 所有堆操作的时间复杂度均为 O (log n)

常用函数

函数 功能
make_heap(first, last) 将区间 [first, last) 构建成一个堆
push_heap(first, last) 将最后一个元素插入到堆中(需先将元素加到容器末尾)
pop_heap(first, last) 将堆顶元素移到区间末尾,剩余元素重新调整为堆
sort_heap(first, last) 将堆转换为有序区间(升序)
is_heap(first, last) 判断区间是否是一个堆(C++11)

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> heap = {3, 1, 4, 1, 5, 9, 2, 6};

    // 1. 构建大顶堆
    std::make_heap(heap.begin(), heap.end());
    // 堆顶元素是最大值:9
    std::cout << "堆顶元素:" << heap.front() << std::endl; // 输出:9

    // 2. 插入元素
    heap.push_back(7); // 先加到末尾
    std::push_heap(heap.begin(), heap.end()); // 调整为堆
    // 现在堆顶还是9

    // 3. 删除堆顶元素
    std::pop_heap(heap.begin(), heap.end()); // 堆顶移到末尾
    heap.pop_back(); // 真正删除
    // 新堆顶:7

    // 4. 堆排序(升序)
    std::sort_heap(heap.begin(), heap.end());
    // heap:{1, 1, 2, 3, 4, 5, 6, 7}

    return 0;
}

10. 二分查找算法

核心特性

  • 要求区间必须是有序的(默认升序)
  • 时间复杂度:O (log n),远快于线性查找的 O (n)
  • 适用于大规模有序数据的查找

常用函数

函数 功能 返回值
binary_search(first, last, value) 判断 value 是否存在于区间中 bool
lower_bound(first, last, value) 查找第一个大于等于 value 的元素 迭代器
upper_bound(first, last, value) 查找第一个大于 value 的元素 迭代器
equal_range(first, last, value) 返回等于 value 的元素区间 pair <迭代器,迭代器>

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 4, 4, 5, 6};

    // 1. 判断元素是否存在
    bool exists = std::binary_search(vec.begin(), vec.end(), 4);
    std::cout << "4是否存在:" << std::boolalpha << exists << std::endl; // 输出:true

    // 2. 查找第一个大于等于4的元素
    auto it_low = std::lower_bound(vec.begin(), vec.end(), 4);
    std::cout << "第一个>=4的元素位置:" << it_low - vec.begin() << std::endl; // 输出:3

    // 3. 查找第一个大于4的元素
    auto it_high = std::upper_bound(vec.begin(), vec.end(), 4);
    std::cout << "第一个>4的元素位置:" << it_high - vec.begin() << std::endl; // 输出:6

    // 4. 统计等于4的元素个数
    int cnt = it_high - it_low;
    std::cout << "4的个数:" << cnt << std::endl; // 输出:3

    return 0;
}

11. 交换算法

核心特性

  • 交换两个元素或两个区间的元素
  • 是 STL 中最基础的算法之一,被其他算法广泛调用

常用函数

函数 功能
swap(a, b) 交换两个对象 ab 的值
iter_swap(it1, it2) 交换两个迭代器 it1it2 指向的元素
swap_ranges(first1, last1, first2) 交换两个区间的元素

用法示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 1. 交换两个变量
    int a = 10, b = 20;
    std::swap(a, b);
    std::cout << "a=" << a << ", b=" << b << std::endl; // 输出:a=20, b=10

    // 2. 交换两个迭代器指向的元素
    std::vector<int> vec = {1, 2, 3, 4};
    std::iter_swap(vec.begin(), vec.end() - 1);
    // vec:{4, 2, 3, 1}

    // 3. 交换两个区间的元素
    std::vector<int> vec1 = {1, 2, 3};
    std::vector<int> vec2 = {4, 5, 6};
    std::swap_ranges(vec1.begin(), vec1.end(), vec2.begin());
    // vec1:{4, 5, 6}, vec2:{1, 2, 3}

    return 0;
}
相关推荐
一条泥憨鱼1 小时前
Java网络编程:Socket通信从入门到起飞
java·开发语言·网络·网络编程
hope_wisdom1 小时前
C/C++数据结构之二叉树基础
c语言·数据结构·c++·二叉树
Hiter_John1 小时前
Golang的条件判断
服务器·开发语言·golang
8Qi81 小时前
LeetCode 474:一和零(Ones and Zeroes)—— 题解 ✅
算法·leetcode·职场和发展·动态规划·01背包
27669582921 小时前
谷歌google cookie逆向角度分析
开发语言·python·google·sgss·谷歌搜索·sg-ss·谷歌cookie逆向
stolentime1 小时前
CF2066D2 Club of Young Aircraft Builders (hard version)题解
c++·算法·动态规划·组合数学
时寒的笔记1 小时前
瑞数案例欧冶解读py和js文件最终版
开发语言·javascript·ecmascript
zmzb01031 小时前
Python课后习题训练记录Day123
开发语言·python
艾莉丝努力练剑1 小时前
【Qt】事件
服务器·开发语言·网络·数据库·qt·tcp/ip·计算机网络