C++: STL 算法

第34课我们学了STL容器,知道了用什么装数据

但光有容器还不够——你还需要处理数据:查找、排序、统计、变换……

如果自己写,可能要写几十行;用STL算法,一行搞定


1. STL算法概述

(1) 1.1 什么是STL算法?

STL算法是C++标准库提供的一组通用函数模板,用于操作容器中的数据。

为什么要用STL算法?

自己写 STL算法
要写循环 一行代码
容易出错 经过严格测试
性能不一定高 高度优化
代码长 代码简洁

生活类比:


(2) 1.2 算法头文件

大多数STL算法在 algorithm 头文件中,数值算法在 numeric 中。

▶ 示例 2:STL算法应用(难度⭐)

CPP
#include <algorithm> // 大多数算法
#include <numeric> // 数值算法(accumulate等)
▶ 试一试

输出:

TEXT 📖 仅展示
(程序输出)

(3) 1.3 算法分类

STL算法按功能分为几大类:

类别 代表算法 说明
非修改算法 findcountfor_each 不修改容器内容
修改算法 copytransformreplace 修改容器内容
排序算法 sortstable_sortpartial_sort 排序相关
二分查找 binary_searchlower_bound 在已排序区间查找
合并算法 mergeinplace_merge 合并有序区间
数值算法 accumulateinner_product 数值计算
集合算法 set_unionset_intersection 集合运算


2. 非修改算法

(1) 2.1 find——查找元素

功能: 在容器中查找指定元素,返回迭代器。

原型:

CPP
InputIt find(InputIt first, InputIt last, const T& value);

示例:查找成绩(难度⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
 std::vector<int> scores = {85, 92, 78, 90, 88};
 
 // 查找成绩90
 auto it = std::find(scores.begin(), scores.end(), 90);
 
 if (it != scores.end()) {
 // 计算位置(索引)
 int index = std::distance(scores.begin(), it);
 std::cout << "找到成绩90,位置:" << index << std::endl;
 } else {
 std::cout << "没找到成绩90" << std::endl;
 }
 
 return 0;
}

运行结果:

TEXT 📖 仅展示
找到成绩90,位置:3

💡 提示:


(2) 2.2 count——计数

功能: 统计容器中等于指定值的元素个数。

示例:统计满分人数(难度⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
 std::vector<int> scores = {100, 85, 100, 92, 78, 100};
 
 // 统计满分(100分)人数
 int perfect = std::count(scores.begin(), scores.end(), 100);
 
 std::cout << "满分人数:" << perfect << std::endl; // 输出:3
 
 return 0;
}

(3) 2.3 for_each——遍历

功能: 对容器中每个元素执行指定操作。

示例:打印所有成绩(难度⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
 std::vector<int> scores = {85, 92, 78, 90, 88};
 
 // 使用 lambda 表达式打印每个成绩
 std::for_each(scores.begin(), scores.end(), (int s) {
 std::cout << s << " ";
 });
 std::cout << std::endl;
 
 return 0;
}

运行结果:

TEXT 📖 仅展示
85 92 78 90 88 

💡 提示:



3. 修改算法

(1) 3.1 copy——复制

功能: 将一个区间的元素复制到另一个区间。

示例:数组复制(难度⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
 std::vector<int> src = {1, 2, 3, 4, 5};
 std::vector<int> dst(5); // 目标容器,大小5
 
 // 复制
 std::copy(src.begin(), src.end(), dst.begin());
 
 // 打印结果
 for (int x : dst) {
 std::cout << x << " ";
 }
 std::cout << std::endl;
 
 return 0;
}

(2) 3.2 transform——变换

功能: 将一个区间的元素变换后复制到另一个区间。

示例:成绩加权(难度⭐⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
 std::vector<int> scores = {85, 92, 78, 90, 88};
 std::vector<int> adjusted(scores.size()); // 调整后成绩
 
 // 平时成绩占70%,考试占30%
 std::transform(scores.begin(), scores.end(), adjusted.begin(),
 (int s) { return s * 0.7 + 90 * 0.3; });
 
 std::cout << "调整后成绩:";
 for (int x : adjusted) {
 std::cout << x << " ";
 }
 std::cout << std::endl;
 
 return 0;
}

运行结果:

TEXT 📖 仅展示
调整后成绩:86.5 91.9 81.6 90 88.6 

(3) 3.3 replace——替换

功能: 将容器中等于某个值的元素替换为另一个值。

示例:补考成绩处理(难度⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
 std::vector<int> scores = {85, 92, 78, 90, 88};
 
 // 将不及格的成绩(<60)替换为60(补考及格线)
 std::replace_if(scores.begin(), scores.end(),
 (int s) { return s < 60; },
 60);
 
 std::cout << "处理后成绩:";
 for (int x : scores) {
 std::cout << x << " ";
 }
 std::cout << std::endl;
 
 return 0;
}


4. 排序算法

(1) 4.1 sort——排序

功能: 对容器区间排序(默认升序)。

示例:成绩排序(难度⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
 std::vector<int> scores = {85, 92, 78, 90, 88};
 
 // 升序排序
 std::sort(scores.begin(), scores.end());
 
 std::cout << "升序排序:";
 for (int x : scores) {
 std::cout << x << " ";
 }
 std::cout << std::endl;
 
 // 降序排序
 std::sort(scores.begin(), scores.end(), std::greater<int>());
 
 std::cout << "降序排序:";
 for (int x : scores) {
 std::cout << x << " ";
 }
 std::cout << std::endl;
 
 return 0;
}

运行结果:

TEXT 📖 仅展示
升序排序:78 85 88 90 92 
降序排序:92 90 88 85 78 

(2) 4.2 自定义排序规则

示例:按成绩高低排序学生(难度⭐⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

struct Student {
 std::string name;
 int score;
};

int main() {
 std::vector<Student> students = {
 {"张三", 85},
 {"李四", 92},
 {"王五", 78}
 };
 
 // 按成绩降序排序
 std::sort(students.begin(), students.end(),
 (const Student& a, const Student& b) {
 return a.score > b.score;
 });
 
 std::cout << "成绩排名:" << std::endl;
 for (const auto& s : students) {
 std::cout << s.name << ":" << s.score << std::endl;
 }
 
 return 0;
}

运行结果:

TEXT 📖 仅展示
成绩排名:
李四:92
张三:85
王五:78


5. 数值算法

(1) 5.1 accumulate——累加

功能: 计算区间内元素的累加和。

示例:计算总分(难度⭐)

CPP
#include <iostream>
#include <vector>
#include <numeric>

int main() {
 std::vector<int> scores = {85, 92, 78, 90, 88};
 
 // 计算总分
 int total = std::accumulate(scores.begin(), scores.end(), 0);
 
 std::cout << "总分:" << total << std::endl; // 输出:433
 std::cout << "平均分:" << total / 5.0 << std::endl; // 输出:86.6
 
 return 0;
}

(2) 5.2 内层乘积

示例:向量点积(难度⭐⭐)

CPP
#include <iostream>
#include <vector>
#include <numeric>

int main() {
 std::vector<int> v1 = {1, 2, 3};
 std::vector<int> v2 = {4, 5, 6};
 
 // 计算点积:1*4 + 2*5 + 3*6 = 32
 int dot_product = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0);
 
 std::cout << "向量点积:" << dot_product << std::endl; // 输出:32
 
 return 0;
}


6. 综合示例

▶ 示例 1:成绩分析系统(难度⭐⭐⭐)

CPP
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <string>

int main() {
 std::vector<int> scores = {85, 92, 78, 90, 88, 76, 95, 83, 89, 91};
 
 // 1. 计算总人数
 int count = scores.size();
 std::cout << "总人数:" << count << std::endl;
 
 // 2. 计算总分和平均分
 int total = std::accumulate(scores.begin(), scores.end(), 0);
 double average = static_cast<double>(total) / count;
 std::cout << "总分:" << total << ",平均分:" << average << std::endl;
 
 // 3. 查找最高分和最低分
 int max_score = *std::max_element(scores.begin(), scores.end());
 int min_score = *std::min_element(scores.begin(), scores.end());
 std::cout << "最高分:" << max_score << ",最低分:" << min_score << std::endl;
 
 // 4. 统计及格人数
 int passed = std::count_if(scores.begin(), scores.end(),
 (int s) { return s >= 60; });
 std::cout << "及格人数:" << passed << std::endl;
 
 // 5. 排序并输出前3名
 std::vector<int> top3 = scores;
 std::sort(top3.begin(), top3.end(), std::greater<int>());
 std::cout << "前3名:";
 for (int i = 0; i < 3; i++) {
 std::cout << top3[i] << " ";
 }
 std::cout << std::endl;
 
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
85 92 78 90 88 76 95 83 89 91

运行结果:

TEXT 📖 仅展示
总人数:10
总分:867,平均分:86.7
最高分:95,最低分:76
及格人数:10
前3名:95 92 91 


7. 算法使用技巧

(1) 7.1 迭代器辅助函数

函数 功能
std::distance(first, last) 计算两个迭代器之间的距离
std::advance(it, n) 将迭代器前进n步
std::next(it) 返回下一个迭代器
std::prev(it) 返回前一个迭代器

(2) 7.2 Lambda表达式进阶

Lambda表达式是STL算法的好搭档:

CPP
// 基本形式
[capture](parameters) -> return_type { body }

// 示例:按多个条件排序
std::sort(students.begin(), students.end(),
 (const Student& a, const Student& b) {
 if (a.score != b.score)
 return a.score > b.score; // 先按成绩
 return a.name < b.name; // 再按姓名
 });

❓ 常见问题

Q STL算法和循环哪个快?
A STL算法通常更快,因为: - 经过高度优化 - 针对不同容器有特化版本 - 编译器可以更好地优化

Q 所有容器都能用STL算法吗?
A 理论上可以,但效率不同: - 顺序容器(vectordeque):效率高 - 关联容器(setmap):有自己成员函数,用成员函数更快

Q:Lambda表达式是什么? A:Lambda是C++11引入的匿名函数,可以在需要函数的地方直接定义。

基本语法:

CPP
[capture](params) -> return_type { body }

示例:

CPP
auto add = (int a, int b) { return a + b; };
std::cout << add(3, 5) << std::endl; // 输出:8

Q 算法报错怎么办?
A 常见错误: 1. 容器未排序就用二分查找 → 先排序 2. 目标容器空间不足 → 用 back_inserter 3. 迭代器类型不匹配 → 检查容器类型

▶ 示例 3:sort排序(难度⭐)

CPP
#include <iostream>
#include <algorithm>
#include <vector>

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

    std::sort(v.begin(), v.end());

    for (int x : v) {
        std::cout << x << " ";
    }
    std::cout << std::endl;

    return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
1 2 3 4 5
💡 提示std::sort 默认升序排序,传入迭代器范围 [begin, end)


📖 小节

学习建议:


📝 作业

  1. **基础题 (Difficulty ⭐):创建一个 vector<int> 包含 10 个随机数,用 sort 排序后输出,再用 reverse 反转后输出。

  2. **进阶题 (Difficulty ⭐⭐):用 find 在 vectorstring 中查找指定字符串,用 count 统计某个值出现的次数。

  3. **挑战题 (Difficulty ⭐⭐⭐):用 remove_if 和 lambda 实现"删除 vector 中所有偶数"的操作。理解 erase-remove 惯用法。



下一课: 实战:OOP综合(#36)—— 用面向对象思想重构学生管理系统

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏