导读:本期聚焦于小伙伴创作的《C++ STL中的算法有哪些常见用法?一文理清排序查找与遍历技巧》,敬请观看详情。写业务代码时经常要处理容器里的数据,但不少人只习惯手写for循环,忽略了STL算法带来的简洁与稳定。STL算法位于algorithm头文件,覆盖排序、查找、遍历、变换等操作,配合迭代器能直接作用于vector、list等容器。比如sort可自定义比较规则完成降序排列,find在有序区间用binary_search更高效,for_each则把循环体抽成函数对象。弄清这些算法的适用场景与复杂度,能减少重复代码,也避免手动实现出错。本文以具体代码演示常见用法与易错点。

STL(标准模板库)的算法组件是C++泛型编程的核心之一,它们以函数模板形式提供,通过迭代器解耦了容器与操作逻辑。在实际工程中,合理运用这些算法不仅能缩短代码量,还能借助标准库经过充分测试的实现来降低缺陷率。常见算法集中在排序、查找、遍历与变换几类,下面通过具体用法逐一说明。

C++ STL中的算法有哪些常见用法?一文理清排序查找与遍历技巧

排序类算法的常见用法

排序是开发中最频繁遇到的需求之一。STL提供了sortstable_sortpartial_sort等接口。其中sort采用内省排序,平均时间复杂度为O(n log n),但不保证相等元素的原有顺序;若需要稳定排序,应使用stable_sort

对于自定义类型或特殊顺序,可以传入函数对象或lambda表达式作为比较器。下面的例子演示了对整数向量做降序排列,以及对结构体按成员排序:

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

struct Student {
    int id;
    int score;
};

int main() {
    std::vector<int> nums = {5, 2, 9, 1, 5, 6};
    // 降序排序
    std::sort(nums.begin(), nums.end(), [](int a, int b) {
        return a > b;
    });
    for (int v : nums) {
        std::cout << v << " ";
    }
    std::cout << std::endl;

    std::vector<Student> stus = {{1, 80}, {2, 95}, {3, 80}};
    // 按分数降序,分数相同按id升序
    std::stable_sort(stus.begin(), stus.end(), [](const Student& a, const Student& b) {
        if (a.score != b.score) return a.score > b.score;
        return a.id < b.id;
    });
    return 0;
}

使用排序算法时要注意,被排序的区间必须是随机访问迭代器(如vector、deque),list容器应使用其成员函数sort。另外,比较器必须满足严格弱序关系,否则会导致未定义行为。

当只需要前k个最大元素而无需全排时,partial_sort会更高效。它在内部将区间前k个元素排好序,其余元素不保证顺序,适合排行榜截取等场景。

查找类算法的使用方式

STL的查找算法包括findfind_ifbinary_searchlower_boundupper_bound。线性查找find适用于未排序区间,时间复杂度O(n);若数据已排序,应使用二分查找系列以获得O(log n)性能。

以下代码展示了在未排序向量中查找偶数,以及在已排序向量中用lower_bound定位首个不小于目标值的元素:

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

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
    // 查找第一个偶数
    auto it = std::find_if(v.begin(), v.end(), [](int x) {
        return x % 2 == 0;
    });
    if (it != v.end()) {
        std::cout << "first even: " << *it << std::endl;
    }

    std::vector<int> sorted = {1, 2, 2, 3, 4, 5};
    // 已排序区间的二分查找
    auto pos = std::lower_bound(sorted.begin(), sorted.end(), 2);
    std::cout << "lower_bound of 2 at index: " << (pos - sorted.begin()) << std::endl;
    return 0;
}

binary_search仅返回是否存在,而lower_boundupper_bound能给出插入位置,二者结合可得到等于某值的所有元素区间。对于频繁查询的场景,先排序再使用二分算法比反复线性查找有明显性能优势。

需要注意,二分类算法要求区间已按对应比较规则排序,且比较规则须与排序时一致,否则结果不可预期。若使用自定义比较器,排序和查找都应传入相同逻辑。

遍历与变换算法的实践

遍历类算法以for_each为代表,它将区间每个元素传给指定函数。配合lambda可替代手写循环,使意图更清晰。变换类如transform则把一个区间映射为另一个区间,常用于数据规整。

下面示例用for_each打印元素,并用transform将整数向量每个元素平方后写入新向量:

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

int main() {
    std::vector<int> a = {1, 2, 3, 4};
    std::for_each(a.begin(), a.end(), [](int x) {
        std::cout << x * x << " ";
    });
    std::cout << std::endl;

    std::vector<int> b(a.size());
    std::transform(a.begin(), a.end(), b.begin(), [](int x) {
        return x * x;
    });
    return 0;
}

for_each的返回值是传入的函数对象,若该函数对象有内部状态,可借此收集遍历过程中的统计信息。而transform要求输出区间有足够空间,通常先用resize扩容或直接使用插入迭代器。

在C++17之后,许多算法增加了执行策略参数(如std::execution::par),可在不改变调用形式的情况下启用并行化,对大区间的for_eachsort等提升吞吐量,但需注意线程安全与数据竞争问题。

其他易忽略的实用算法

除了上述三类,STL还提供countaccumulate(在<numeric>中)、uniquereverse等。比如unique配合erase可去除有序区间相邻重复项,accumulate能做求和或自定义折叠。

示例展示如何删除向量中相邻重复值并统计总和:

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

int main() {
    std::vector<int> v = {1, 1, 2, 2, 3, 3, 3};
    // 先排序保证相同元素相邻
    std::sort(v.begin(), v.end());
    auto last = std::unique(v.begin(), v.end());
    v.erase(last, v.end());
    int sum = std::accumulate(v.begin(), v.end(), 0);
    std::cout << "sum after unique: " << sum << std::endl;
    return 0;
}

这些算法大多语义明确、副作用可控,比手写的临时循环更容易评审与维护。建议开发中遇到容器数据处理时,先查阅标准库是否已提供对应算法,再决定是否自行实现。

总体而言,STL算法通过迭代器抽象屏蔽了容器差异,在排序、查找、遍历等场景都能提供高效且安全的实现。掌握它们的参数约定与复杂度特征,是写出简洁C++代码的重要一步。

C++_STLSTL_algorithms排序查找修改时间:2026-07-31 23:30:46

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。