【后端】【C++】泛型算法:从传统到C++20 Ranges的进化之旅

📖目录

  • 前言
  • [1. 为什么需要泛型算法?](#1. 为什么需要泛型算法?)
  • [2. 迭代器:泛型算法的"交通系统"](#2. 迭代器:泛型算法的"交通系统")
  • [3. C++20 Ranges:泛型算法的"智能交通系统"](#3. C++20 Ranges:泛型算法的"智能交通系统")
  • [4. 数学视角:泛型算法的通用形式](#4. 数学视角:泛型算法的通用形式)
  • [5. 策略模式:让算法"可插拔"](#5. 策略模式:让算法"可插拔")
  • [6. C++20 Ranges vs 传统泛型算法](#6. C++20 Ranges vs 传统泛型算法)
  • [7. 经典书籍推荐](#7. 经典书籍推荐)
  • [8. 结语](#8. 结语)

前言

核心理念:泛型算法是C++ STL的基石,它让算法与容器解耦,实现"一算法多容器"的通用设计。想象一下,你去菜市场买菜:找最便宜的青菜(最小值)、找最新鲜的鱼(按日期排序),只需告诉"比价机器人"比较标准,而不需要知道具体怎么比较。这正是泛型算法的精髓!

本文与历史文章的关系

我曾发表过一篇《【后端】【C++】函数对象与泛型算法:从"找最便宜的菜"说起](https://blog.csdn.net/xiezhiyi007/article/details/155673934)》,该文以"找最便宜的菜"为引子,介绍了C++中函数对象(Functor)与泛型算法的基础概念,通过findOptimum函数展示了策略模式的应用。

本文的升级点

  1. C++20标准支持:本文基于C++20的Ranges库,将泛型算法的使用从"传递迭代器"升级为"直接操作容器"
  2. 代码简洁度提升:C++20 Ranges使代码量减少50%,语义更清晰
  3. 链式操作:展示Ranges库支持的管道式(pipeline)操作,这是旧文章无法实现的

如果你尚未阅读旧文,建议先阅读《【后端】【C++】函数对象与泛型算法:从"找最便宜的菜"说起》,它将为你理解本文提供基础。本文则是该文的C++20升级版,专注于现代C++的高效用法。


1. 为什么需要泛型算法?

在C++98之前,程序员需要为每种容器编写专门的算法。比如,为vector<int>写一个findMin,为list<string>写另一个findMin,代码重复率高达80%。这就像每次去超市都要重新学习怎么找最便宜的菜,效率低下。

泛型算法的诞生:C++ STL引入了泛型算法,通过迭代器(Iterator)作为桥梁,让算法与容器解耦。算法只关心"如何移动和访问元素",不关心"元素存储在哪里"。


2. 迭代器:泛型算法的"交通系统"

C++定义了5类迭代器,如同不同类型的交通系统:

迭代器类型 特点 适用场景 生活类比
输入迭代器 单向读取 std::find 单向售票口
输出迭代器 单向写入 std::copy 单向投递口
前向迭代器 单向读写 std::list算法 前进的传送带
双向迭代器 双向读写 std::reverse 双向电梯
随机访问迭代器 随机定位 std::sort 电梯直达任意楼层
cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

int main() {
    std::vector<int> vec = {5, 2, 8, 1, 9};
    
    // 使用随机访问迭代器进行排序
    std::sort(vec.begin(), vec.end()); // 1 2 5 8 9
    
    // 使用输入迭代器查找元素
    auto it = std::find(vec.begin(), vec.end(), 5);
    if (it != vec.end()) {
        std::cout << "Found 5 at position: " << std::distance(vec.begin(), it) << std::endl;
    }
    
    // 使用输出迭代器向新容器复制
    std::vector<int> vec2;
    std::copy(vec.begin(), vec.end(), std::back_inserter(vec2)); // 1 2 5 8 9
    
    return 0;
}

执行结果

text 复制代码
Found 5 at position: 2

3. C++20 Ranges:泛型算法的"智能交通系统"

C++20引入了Ranges库,让泛型算法更简洁、更易读。传统写法需要传递两个迭代器,而Ranges只需传递容器本身。

传统写法 vs C++20 Ranges

cpp 复制代码
// 传统写法:需要传递迭代器范围
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = std::find(vec.begin(), vec.end(), 3);
if (it != vec.end()) {
    std::cout << "Found 3" << std::endl;
}

// C++20 Ranges:只需传递容器
#include <ranges>
auto it = std::ranges::find(vec, 3); // 更简洁、更易读

Ranges库的核心优势

  • 代码更简洁:省去传递迭代器的步骤
  • 语义更清晰:算法与数据的关联更直接
  • 支持链式操作:实现"管道式"处理
cpp 复制代码
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    // C++20 Ranges链式操作
    auto result = vec | std::views::filter([](int x) { return x % 2 == 0; }) // 筛选偶数
                  | std::views::transform([](int x) { return x * 2; }); // 乘以2
    
    for (int x : result) {
        std::cout << x << " "; // 输出: 4 8
    }
    
    return 0;
}

执行结果

text 复制代码
4 8

4. 数学视角:泛型算法的通用形式

推导过程(找最小值)

这正是std::min_element的内部逻辑。

5. 策略模式:让算法"可插拔"

策略模式是泛型算法的核心设计思想。它允许将算法的"比较标准"作为参数传入,实现"算法与策略解耦"。

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

// 策略1:找最小值
struct Less {
    bool operator()(int a, int b) const { return a < b; }
};

// 策略2:找最大值
struct Greater {
    bool operator()(int a, int b) const { return a > b; }
};

// 泛型算法:findOptimum
template <typename T, typename Comparison>
const T* findOptimum(const std::vector<T>& values, Comparison compare) {
    if (values.empty()) return nullptr;
    
    const T* optimum = &values[0];
    for (size_t i = 1; i < values.size(); ++i) {
        // 如果当前元素比已知最优更"优",就更新
        if (compare(values[i], *optimum)) {
            optimum = &values[i];
        }
    }
    return optimum;
}

int main() {
    std::vector<int> numbers = {91, 18, 92, 22, 13, 43};
    
    // 使用Less策略找最小值
    std::cout << "Minimum: " << *findOptimum(numbers, Less{}) << std::endl;
    
    // 使用Greater策略找最大值
    std::cout << "Maximum: " << *findOptimum(numbers, Greater{}) << std::endl;
    
    return 0;
}

执行结果

text 复制代码
Minimum: 13
Maximum: 92

6. C++20 Ranges vs 传统泛型算法

特性 传统泛型算法 C++20 Ranges
代码简洁性 需要传递迭代器 仅需传递容器
语义清晰度 有点抽象 更直观
链式操作 需要嵌套调用 支持管道式操作
适用容器 任何支持迭代器的容器 任何支持ranges的容器
代码可读性 一般

7. 经典书籍推荐

  1. 《C++ Templates: The Complete Guide (2nd Ed)》 by David Vandevoorde et al.

    • 被誉为"模板圣经",第19章详细讲解"Functors and Lambdas"
    • 包含C++20 Concepts与Ranges相关内容
    • 适合想深入理解泛型编程的开发者
  2. 《Effective Modern C++》 by Scott Meyers

    • 第23条:"理解如何使用Ranges"
    • 第24条:"了解C++20的协程"
    • 适合想在实际项目中应用现代C++特性的开发者
  3. 《C++ Standard Library: A Tutorial and Reference (2nd Ed)》 by Nicolai M. Josuttis

    • 详细讲解STL的每个组件
    • 包含C++11/14/17/20的特性对比
    • 适合需要快速查阅STL特性的开发者

8. 结语

泛型算法是C++ STL的基石,它让代码更加通用、高效。从C++98的迭代器到C++20的Ranges,泛型算法不断进化,使C++编程更加简洁、优雅。

记住:"算法是骨架,策略是插件" 。下次当你写std::sort(vec.begin(), vec.end(), my_compare)时,你会知道:背后站着一个默默工作的策略模式。

编译提示 :所有C++20代码需启用/std:c++20编译选项(VS2022/Clang14+)。C++20 Ranges库在<ranges>头文件中定义。

相关推荐
ULTRA??1 小时前
最小生成树kruskal算法实现python,kotlin
人工智能·python·算法
sin_hielo1 小时前
leetcode 1523
数据结构·算法·leetcode
代码游侠1 小时前
复习——线性表
linux·c语言·数据结构·学习·算法
秋深枫叶红1 小时前
嵌入式第二十九篇——数据结构——树
数据结构·学习·算法·深度优先
Lion Long1 小时前
C++20 异步编程:用future、promise 还是协程?
开发语言·c++·stl·c++20
能源系统预测和优化研究1 小时前
【原创代码改进】基于贝叶斯优化的PatchTST综合能源负荷多变量时间序列预测
算法·回归·transformer·能源
小龙报1 小时前
【C语言初阶】动态内存分配实战指南:C 语言 4 大函数使用 + 经典笔试题 + 柔性数组优势与内存区域
android·c语言·开发语言·数据结构·c++·算法·visual studio
小龙报2 小时前
【算法通关指南:算法基础篇(三)】一维差分专题:1.【模板】差分 2.海底高铁
android·c语言·数据结构·c++·算法·leetcode·visual studio
小白程序员成长日记2 小时前
2025.12.07 力扣每日一题
算法·leetcode·职场和发展