当前位置:首页 > 技术 > 正文内容

C++ STL 算法库核心功能详解

访客 技术 2026年9月1日 1

引言

C++ 标准模板库(STL)提供了一组通用的算法,位于<algorithm>头文件中。这些算法设计为与容器解耦,通过迭代器操作数据序列。根据是否改变底层数据结构,主要分为非修改性算法和修改性算法。

一、非修改性序列操作

此类函数仅读取数据,不会更改容器内的元素状态或顺序。

1.1 查找类算法

包括基础的数值匹配和条件判断。

  • find():返回首次匹配特定值的迭代器。
  • find_if():返回首个满足自定义条件的元素位置。
  • search_n():查找连续重复元素序列。
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> dataSet = {10, 20, 30, 40, 50};

    // 查找数值 30 的索引
    auto it = std::find(dataSet.begin(), dataSet.end(), 30);
    if (it != dataSet.end()) {
        std::cout << "Found value at index: " << (it - dataSet.begin()) << std::endl;
    }

    // 寻找第一个大于 25 的数字
    auto conditionIt = std::find_if(dataSet.begin(), dataSet.end(), [](int val) {
        return val > 25;
    });
    
    return 0;
}

1.2 统计与遍历

  • count() / count_if():统计符合指定值的数量。
  • for_each():对每个元素执行 Lambda 表达式或函数对象。
#include <numeric>
// 统计偶数个数
int evenCount = std::count_if(dataSet.begin(), dataSet.end(), [](int n){ return n % 2 == 0; });

// 应用操作
std::for_each(dataSet.begin(), dataSet.end(), [](int& item){ 
    item += 10; // 原地累加
});

1.3 范围比较与性质检查

  • equal():检测两个区间内容是否完全一致。
  • mismatch():返回第一个不匹配元素的迭代器对。
  • all_of() / any_of() / none_of():判断范围内是否存在全部或部分满足条件的元素。
std::vector<int> vecA = {5, 6, 7};
std::vector<int> vecB = {5, 6, 8};

// 检查是否所有元素均为正数
bool allPositive = std::all_of(vecA.begin(), vecA.end(), [](int x){ return x > 0; });
// 结果:true

二、修改性序列操作

这类算法会直接变动容器中的内容、结构或容量。

2.1 复制与变换

  • copy() / copy_if():将源数据写入目标地址,支持谓词过滤。
  • transform():应用一元或二元操作,生成新数据序列。
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> target(5);

// 平方运算转换
std::transform(source.begin(), source.end(), target.begin(), [](int x){
    return x * x;
});
// target 现为 {1, 4, 9, 16, 25}

// 双源相加
std::vector<int> src2 = {5, 5, 5, 5, 5};
std::vector<int> sumVec(5);
std::transform(source.begin(), source.end(), src2.begin(), sumVec.begin(), 
    [](int a, int b){ return a + b; });

2.2 替换与删除(重要模式)

  • replace():原地修改值。
  • remove():注意此函数并未真正减小容器大小,而是将有效元素前移,并返回新的尾迭代器。需结合 erase() 实现物理删除。
  • unique():移除相邻重复项(需预排序)。
std::vector<int> numList = {1, 5, 5, 3, 2, 2, 1};

// 逻辑删除值为 5 的元素
auto newEnd = std::remove(numList.begin(), numList.end(), 5);
// 此时容器末尾是无效数据

// 物理删除:调整实际大小
numList.erase(newEnd, numList.end()); 

// 删除重复相邻元素
std::vector<int> dupList = {1, 1, 2, 3, 3};
auto last = std::unique(dupList.begin(), dupList.end());
dupList.erase(last, dupList.end()); // 变为 {1, 2, 3}

2.3 重排与随机化

  • reverse():逆序区间。
  • rotate():循环位移。
  • shuffle():随机打乱(C++11 及以后)。
#include <random>
std::vector<int> cards = {1, 2, 3, 4, 5};

// 反转
std::reverse(cards.begin(), cards.end());

// 旋转:使中间元素成为起点
std::rotate(cards.begin(), cards.begin() + 1, cards.end());

// 洗牌
std::random_device rd;
std::mt19937 gen(rd());
std::shuffle(cards.begin(), cards.end(), gen);

三、排序及相关操作

有序数据能显著提升查找和合并效率。

3.1 基础排序

  • sort():通常基于 Introsort,不稳定,复杂度 O(N log N)。
  • stable_sort():保持稳定顺序,适用于多关键字排序场景。
  • partial_sort():仅保证前半部分有序。
struct Item { int id; double price; };
std::vector<Item> list = {{1, 10.5}, {2, 5.2}, {3, 10.5}};

// 按价格降序稳定排序
std::stable_sort(list.begin(), list.end(), [](const Item& a, const Item& b){
    return a.price > b.price;
});

3.2 选择与二分查找

  • nth_element():快速找到第 N 小的元素,类似快速选择算法。
  • binary_search() / lower_bound() / upper_bound():要求容器已排序。
// 假设 sortedData 已升序排列
std::vector<int> sortedData = {10, 20, 30, 40, 50};

// 查找第一个 >= 35 的位置
auto lb = std::lower_bound(sortedData.begin(), sortedData.end(), 35);
// 如果 lb 指向 40,则 35 不存在

3.3 归并

merge():将两个有序区间合并为一个新有序区间。

std::vector<int> left = {1, 3, 5};
std::vector<int> right = {2, 4, 6};
std::vector<int> result(left.size() + right.size());

std::merge(left.begin(), left.end(), 
           right.begin(), right.end(), 
           result.begin());
// result: {1, 2, 3, 4, 5, 6}

四、堆与极值操作

4.1 堆维护

利用 STL 向量模拟优先队列功能。

std::vector<int> heapData = {3, 1, 4, 1, 5};

// 构建最大堆
std::make_heap(heapData.begin(), heapData.end());

// 插入新元素
heapData.push_back(9);
std::push_heap(heapData.begin(), heapData.end());

// 弹出堆顶
std::pop_heap(heapData.begin(), heapData.end());
heapData.pop_back();

4.2 最小/最大值

获取迭代器引用而非单纯数值。

std::vector<int> vals = {9, 1, 7};
auto minRes = std::minmax_element(vals.begin(), vals.end());
// minRes.first 指向最小值 1
// minRes.second 指向最大值 9

五、数值计算工具(numeric)

位于 &lt;numeric&gt; 中,处理数学归纳逻辑。

  • accumulate():累加求和或乘积。
  • iota():填充递增序列。
  • inner_product():计算点积。
#include <numeric>
std::vector<int> nums = {1, 2, 3, 4, 5};

// 求和
int total = std::accumulate(nums.begin(), nums.end(), 0);

// 填充 100 到 104
std::vector<int> seq(5);
std::iota(seq.begin(), seq.end(), 100);

六、集合操作与实用工具

6.1 集合运算

涉及并集、交集等,输入必须有序。

std::vector<int> setA = {1, 2, 3, 4};
std::vector<int> setB = {3, 4, 5, 6};
std::vector<int> diff;

// 差集 (A - B)
std::set_difference(setA.begin(), setA.end(),
                    setB.begin(), setB.end(),
                    std::back_inserter(diff));
// diff 为 {1, 2}

6.2 常见问题解析

Q: remove 为什么没有改变容器大小?
A: 这是为了保持迭代器有效性。它只是覆盖无效数据并返回新结束位置,必须由 erase 完成内存释放。

Q: binary_search 为何需要先排序?
A: 二分查找依赖数据的有序性来排除一半搜索空间,无序导致算法失效。

Q: stable_sort 何时使用?
A: 当相等元素的原始相对顺序对业务逻辑有意义时(如多级排序),应优先使用稳定排序,尽管它会消耗额外空间。

标签: C++STLAlgorithm

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。