《 C++ 零基础入门教程》第6章:模板与 STL 算法 —— 写一次,用万次

✅ 本篇目标:

  • 理解 函数模板类模板
  • 掌握 STL 算法sort, find, for_each
  • 学会使用 lambda 表达式
  • 实战项目:通用计算器 + 学生成绩排序系统
    🕒 建议学习时间:3--4 小时|可分多次完成

💡 本篇将让你写出高度复用、类型安全、性能卓越的代码!


📘 C++ 零基础入门教程(第 6 篇)

模板与 STL 算法 ------ 写一次,用万次


第一步:为什么需要模板?

假设你想写一个函数,求两个数的最大值:

cpp 复制代码
int max(int a, int b) { return (a > b) ? a : b; }
double max(double a, double b) { ... } // 重复!
string max(string a, string b) { ... } // 又重复!

❌ 问题:为每种类型写一遍,代码冗余,难以维护。

✅ 解决方案:函数模板(Function Template)

cpp 复制代码
#include <iostream>
using namespace std;

// 模板声明
template<typename T>
T myMax(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    cout << myMax(3, 5) << endl;           // int
    cout << myMax(3.14, 2.71) << endl;     // double
    cout << myMax(string("Hi"), string("Hello")) << endl; // string

    return 0;
}

✅ 输出:

复制代码
5
3.14
Hi

🔑 关键点:

  • template<typename T> 声明一个类型参数 T
  • 编译器会为每种调用类型自动生成具体函数(称为"实例化")
  • typename 也可写作 class(历史原因),但推荐用 typename

第二步:类模板(Class Template)

同样,我们可以让类支持任意类型。

示例:通用栈(Stack)

cpp 复制代码
#include <vector>
#include <stdexcept>
using namespace std;

template<typename T>
class Stack {
private:
    vector<T> data;

public:
    void push(const T& item) {
        data.push_back(item);
    }

    T pop() {
        if (data.empty()) {
            throw runtime_error("Stack is empty!");
        }
        T top = data.back();
        data.pop_back();
        return top;  // 注意:这里可能拷贝,可用移动优化(第5篇)
    }

    bool empty() const {
        return data.empty();
    }
};

// 使用
int main() {
    Stack<int> intStack;
    intStack.push(10);
    intStack.push(20);
    cout << intStack.pop() << endl; // 20

    Stack<string> strStack;
    strStack.push("Hello");
    strStack.push("C++");
    cout << strStack.pop() << endl; // C++

    return 0;
}

💡 这就是 std::stackstd::vector 的工作原理!


第三步:STL 算法 ------ 不用手写循环!

STL 提供大量通用算法,配合容器使用,代码更简洁、高效、安全。

常用算法头文件:

cpp 复制代码
#include <algorithm>  // sort, find, transform...
#include <numeric>    // accumulate

3.1 std::sort ------ 排序

cpp 复制代码
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

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

    sort(nums.begin(), nums.end()); // 升序
    for (int x : nums) cout << x << " "; // 1 2 5 8 9

    // 降序:传入比较函数
    sort(nums.begin(), nums.end(), greater<int>());
    for (int x : nums) cout << x << " "; // 9 8 5 2 1

    return 0;
}

3.2 自定义排序:对学生按成绩排序

cpp 复制代码
class Student {
public:
    string name;
    double score;
    Student(string n, double s) : name(n), score(s) {}
};

// 方法1:重载 < 运算符
bool operator<(const Student& a, const Student& b) {
    return a.score < b.score;  // 按分数升序
}

// 方法2:用 lambda(推荐!)
int main() {
    vector<Student> students = {
        {"Alice", 95},
        {"Bob", 88},
        {"Charlie", 92}
    };

    // 使用 lambda 自定义排序规则
    sort(students.begin(), students.end(),
         [](const Student& a, const Student& b) {
             return a.score > b.score;  // 降序:高分在前
         });

    for (const auto& s : students) {
        cout << s.name << ": " << s.score << endl;
    }

    return 0;
}

✅ 输出:

复制代码
Alice: 95
Charlie: 92
Bob: 88

🔥 Lambda 表达式[capture](params) { body }

是一种匿名函数,特别适合传给算法!


3.3 其他常用算法

算法 用途
find(begin, end, value) 查找元素
count(begin, end, value) 统计出现次数
accumulate(begin, end, init) 求和(需 <numeric>
transform(...) 批量转换(如平方每个元素)
示例:计算平均分(不用手写循环)
cpp 复制代码
#include <numeric>
double total = accumulate(students.begin(), students.end(), 0.0,
    [](double sum, const Student& s) {
        return sum + s.score;
    });
double avg = total / students.size();

第四步:实战项目 1 ------ 通用计算器(模板版)

支持任意数值类型(int, double, float)的加减乘除。

cpp 复制代码
// calculator.cpp
#include <iostream>
using namespace std;

template<typename T>
class Calculator {
public:
    static T add(T a, T b) { return a + b; }
    static T subtract(T a, T b) { return a - b; }
    static T multiply(T a, T b) { return a * b; }
    static T divide(T a, T b) {
        if (b == 0) throw invalid_argument("Division by zero!");
        return a / b;
    }
};

int main() {
    cout << "整数: " << Calculator<int>::add(3, 5) << endl;
    cout << "浮点: " << Calculator<double>::divide(10.0, 3.0) << endl;

    return 0;
}

✅ 输出:

复制代码
整数: 8
浮点: 3.33333

💡 使用 static 成员函数,无需创建对象。


第五步:实战项目 2 ------ 学生成绩分析系统(STL 算法版)

功能:

  • 按成绩排序(高到低)
  • 找出最高分学生
  • 计算平均分
  • 筛选及格学生
cpp 复制代码
// grade_analysis.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;

struct Student {
    string name;
    double score;
};

void analyzeGrades(vector<Student>& students) {
    // 1. 按分数降序排序
    sort(students.begin(), students.end(),
         [](const Student& a, const Student& b) {
             return a.score > b.score;
         });

    // 2. 打印排序后列表
    cout << "\n--- 排名 ---\n";
    for (size_t i = 0; i < students.size(); ++i) {
        cout << (i + 1) << ". " << students[i].name
             << " (" << students[i].score << ")\n";
    }

    // 3. 计算平均分
    double total = accumulate(students.begin(), students.end(), 0.0,
        [](double sum, const Student& s) {
            return sum + s.score;
        });
    cout << "\n平均分: " << (total / students.size()) << endl;

    // 4. 筛选及格学生(>=60)
    vector<Student> passed;
    copy_if(students.begin(), students.end(), back_inserter(passed),
            [](const Student& s) { return s.score >= 60; });

    cout << "\n及格人数: " << passed.size() << "/" << students.size() << endl;
}

int main() {
    vector<Student> students = {
        {"Alice", 95}, {"Bob", 55}, {"Charlie", 88}, {"David", 45}
    };

    analyzeGrades(students);

    return 0;
}

✅ 输出:

复制代码
--- 排名 ---
1. Alice (95)
2. Charlie (88)
3. Bob (55)
4. David (45)

平均分: 70.75

及格人数: 2/4

🎯 亮点:

  • copy_if + back_inserter:优雅筛选
  • 全程使用 STL 算法,无手动 for 循环
  • 代码清晰、高效、可读性强

📌 本篇小结:你已掌握

概念 说明
函数模板 template<typename T> T func(T a, T b)
类模板 template<typename T> class Container { ... };
STL 算法 sort, find, accumulate, copy_if...
Lambda 表达式 [=](int x) { return x * 2; }
泛型思维 写通用代码,适配多种类型

✅ 下一步建议

  1. 尝试 :用 transform 将所有学生成绩加 5 分
  2. 思考 :如何对 map 按 value 排序?(提示:转成 vector of pairs)
  3. 预习:什么是"异常安全"?如何正确处理错误?

相关推荐
Tim_102 小时前
【算法专题训练】37、前缀树&二叉树
算法
诗意地回家2 小时前
淘宝小游戏反编译
开发语言·前端·javascript
wangkay882 小时前
【Java 转运营】Day04:抖音新号起号前准备全指南
java·开发语言·新媒体运营
点云SLAM2 小时前
C++ 静态初始化顺序问题(SIOF)和SLAM / ROS 工程实战问题
开发语言·c++·slam·静态初始化顺序问题·工程实战技术·c++static 关键字
NineData2 小时前
第三届数据库编程大赛-八强决赛成绩揭晓
数据库·算法·代码规范
D3bugRealm2 小时前
MATLAB解决物理问题:从基础运动学到进阶力学的实战指南
开发语言·其他·matlab
小李独爱秋2 小时前
计算机网络经典问题透视:TLS协议工作过程全景解析
运维·服务器·开发语言·网络协议·计算机网络·php
雍凉明月夜2 小时前
深度学习之目标检测yolo算法Ⅱ(v4)
深度学习·算法·yolo·目标检测
pen-ai3 小时前
打通 Python 与 C++ 的参数传递机制
开发语言·c++·python