STL(Standard Template Library)是 C++ 标准库的核心组成部分,由Alexander Stepanov在惠普实验室开发,它通过泛型编程提供了一套通用的模板类和函数,实现了常见的数据结构和算法。

一.STL 概述

  • C++ 标准模板库(Standard Template Library,STL)是一套功能强大的 C++ 模板类和函数的集合,它提供了一系列通用的、可复用的算法和数据结构。

  • STL 的设计基于泛型编程,这意味着使用模板可以编写出独立于任何特定数据类型的代码。

  • STL 分为多个组件,包括容器(Containers)、迭代器(Iterators)、算法(Algorithms)、函数对象(Function Objects)、适配器(Adapters)和 分配器(Allocators)等。

  • 使用 STL 的好处:
    代码复用:STL 提供了大量的通用数据结构和算法,可以减少重复编写代码的工作。
    性能优化:STL 中的算法和数据结构都经过了优化,以提供最佳的性能。
    泛型编程:使用模板,STL 支持泛型编程,使得算法和数据结构可以适用于任何数据类型。
    易于维护:STL 的设计使得代码更加模块化,易于阅读和维护。

二.STL 的六大组件

组件 功能描述
容器(Containers) 管理数据集合
算法(Algorithms) 操作容器中的元素
迭代器(Iterators) 连接容器和算法的桥梁
函数对象(Function Objects) 使算法更加灵活
适配器(Adapters) 修改或组合组件
分配器(Allocators) 内存管理

1.容器(Containers)

容器是 STL 中最基本的组件之一,用于存储和管理数据集合。所有容器都是模板类,可以存储任意类型的数据。容器提供了各种数据结构,包括向量(vector)、链表(list)、队列(queue)、栈(stack)、集合(set)、映射(map)等。这些容器具有不同的特性和用途,可以根据实际需求选择合适的容器。

1.1序列式容器(顺序容器)

元素按线性顺序排列,每个元素都有固定位置,位置取决于插入的时间和位置。允许双向遍历。

  • vector(动态数组):支持快速随机访问。将元素置于一个动态数组中加以管理,可以随机存取元素(用索引直接存取),数组尾部添加或移除元素非常快速,但是在中部或头部安插元素比较费时。
#include <vector>

// 创建和初始化
vector<int> vec1;                    // 空vector
vector<int> vec2(10, 5);             // 10个5
vector<int> vec3 = {1, 2, 3, 4, 5};  // 初始化列表
vector<int> vec4(vec3);              // 拷贝构造
vector<int> vec5(vec3.begin(), vec3.begin() + 3);  // 范围构造

// 容量操作
cout << "大小: " << vec3.size() << endl;          // 5
cout << "容量: " << vec3.capacity() << endl;      // 5
cout << "是否为空: " << vec3.empty() << endl;     // 0(false)

vec3.reserve(20);                    // 预留容量,不改变大小
vec3.resize(8, 0);                   // 调整大小,新元素初始化为0
vec3.shrink_to_fit();                // 减少容量以匹配大小(C++11)

// 元素访问
vec3[2] = 99;                        // 不检查边界
vec3.at(3) = 88;                     // 检查边界,越界抛异常
cout << "第一个元素: " << vec3.front() << endl;  // 1
cout << "最后一个元素: " << vec3.back() << endl;  // 0(新增的元素)

// 添加元素
vec3.push_back(6);                   // 尾部添加,O(1)平摊
vec3.insert(vec3.begin() + 2, 77);   // 指定位置插入,O(n)
vec3.emplace_back(7);                // 尾部就地构造,避免复制(C++11)

// 删除元素
vec3.pop_back();                     // 尾部删除,O(1)
vec3.erase(vec3.begin() + 1);        // 删除指定位置,O(n)
vec3.erase(vec3.begin() + 1, vec3.begin() + 3);  // 删除范围
vec3.clear();                        // 清空所有元素

// 交换
vector<int> other = {10, 20, 30};
vec3.swap(other);                    // 交换两个vector的内容

// 内存管理技巧
vector<int>().swap(vec3);            // 清空并释放所有内存
  • deque(双端队列):支持快速插入和删除。是“double-ended queue”的缩写,可以随机存取元素(用索引直接存取),数组头部和尾部添加或移除元素都非常快速,但是在中部安插元素比较费时。
#include <deque>

deque<int> dq = {1, 2, 3, 4, 5};

// 两端操作(高效)
dq.push_front(0);                    // 头部插入,O(1)
dq.push_back(6);                     // 尾部插入,O(1)
dq.pop_front();                      // 头部删除,O(1)
dq.pop_back();                       // 尾部删除,O(1)

// 随机访问(高效)
dq[2] = 99;                          // O(1)

// 中间操作(低效)
dq.insert(dq.begin() + 2, 88);       // O(n)

// 应用场景:需要两端快速操作的序列
  • list(双向链表):支持快速插入和删除,但不支持随机访问。不提供随机存取(按顺序走到需存取的元素,O(n)),在任何位置上执行插入或删除动作都非常迅速,内部只需调整一下指针。
#include <list>

list<int> lst = {1, 2, 3, 4, 5};

// 插入和删除(任何位置都高效)
auto it = lst.begin();
advance(it, 2);                      // it指向第3个元素
lst.insert(it, 99);                  // O(1)
lst.erase(it);                       // O(1)

// 链表特有操作
lst.sort();                          // 排序,O(n log n)
lst.unique();                        // 去重相邻重复元素,O(n)
lst.reverse();                       // 反转,O(n)

// 合并和拼接
list<int> lst2 = {6, 7, 8};
lst.merge(lst2);                     // 合并两个有序链表
lst.splice(lst.begin(), lst2);       // 将lst2的所有元素移到lst开头

// 访问元素(不支持随机访问)
for (auto it = lst.begin(); it != lst.end(); ++it) {
    cout << *it << " ";
}

// 应用场景:频繁在任意位置插入删除
  • forward_list(单向链表,C++11引入)
#include <forward_list>

forward_list<int> flst = {1, 2, 3, 4, 5};

// 只能从头部操作
flst.push_front(0);                  // O(1)
flst.pop_front();                    // O(1)

// 插入删除使用after版本
auto it = flst.begin();
flst.insert_after(it, 99);           // 在it后插入
flst.erase_after(it);                // 删除it后的元素

// 更节省内存,但功能受限
  • array(固定数组,C++11引入)
#include <array>

array<int, 5> arr = {1, 2, 3, 4, 5};

// 类似C数组,但有STL接口
arr.fill(0);                         // 填充所有元素为0
cout << "大小: " << arr.size() << endl;        // 5
cout << "是否为空: " << arr.empty() << endl;   // false

// 支持迭代器
for (auto it = arr.begin(); it != arr.end(); ++it) {
    cout << *it << " ";
}

// 编译时确定大小,栈上分配

1.2关联式容器(有序容器)

元素按键(Key)排序,通过键快速访问元素。存储键值对,每个元素都有一个键(key)和一个值(value),并且通过键来组织元素。元素位置取决于特定的排序准则,和插入顺序无关。

  • set(集合):不允许重复元素。内部的元素依据其值自动排序,set 内的相同数值的元素只能出现一次。内部由二叉树实现,便于查找。
#include <set>

set<int> s = {5, 3, 1, 4, 2};  // 自动排序: 1,2,3,4,5

// 插入元素
auto result = s.insert(6);     // 返回pair<iterator, bool>
if (result.second) {
    cout << "插入成功" << endl;
}

// 查找元素
auto it = s.find(3);           // O(log n)
if (it != s.end()) {
    cout << "找到: " << *it << endl;
}

// 边界查找
auto lb = s.lower_bound(3);    // 第一个>=3的迭代器
auto ub = s.upper_bound(3);    // 第一个>3的迭代器

// 范围查找
auto range = s.equal_range(3); // pair<lower_bound, upper_bound>
for (auto it = range.first; it != range.second; ++it) {
    cout << *it << " ";
}

// 删除元素
s.erase(3);                    // 删除值为3的元素
s.erase(it);                   // 删除迭代器指向的元素
s.erase(s.begin(), s.find(3)); // 删除范围

// 自定义比较函数
struct Compare {
    bool operator()(int a, int b) const {
        return a > b;           // 降序排列
    }
};
set<int, Compare> s2 = {1, 2, 3, 4, 5};  // 5,4,3,2,1
  • multiset(多重集合):允许多个元素具有相同的键。内部的元素依据其值自动排序,multiset 内可包含多个数值相同的元素,内部由二叉树实现,便于查找。
#include <set>

multiset<int> ms = {1, 2, 2, 3, 3, 3};

// 允许重复元素
ms.insert(2);                   // 现在有3个2

// 统计元素个数
int count = ms.count(2);        // 返回3

// 查找所有相同元素
auto range = ms.equal_range(2);
for (auto it = range.first; it != range.second; ++it) {
    cout << *it << " ";
}
  • map(映射):每个键映射到一个值。map 的元素是成对的键值 / 实值,内部的元素依据其值自动排序,map 内的相同数值的元素只能出现一次。
#include <map>

map<string, int> m = {
    {"Alice", 25},
    {"Bob", 30},
    {"Charlie", 35}
};

// 插入元素
auto result = m.insert({"David", 40});      // 返回pair<iterator, bool>
m["Eve"] = 45;                               // 如果不存在则插入,存在则修改

// 访问元素
int age = m.at("Alice");                     // 如果不存在则抛出异常
int age2 = m["Bob"];                         // 如果不存在则创建默认值

// 查找元素
auto it = m.find("Charlie");
if (it != m.end()) {
    cout << it->first << ": " << it->second << endl;
}

// 遍历
for (const auto& [key, value] : m) {         // C++17结构化绑定
    cout << key << ": " << value << endl;
}

for (const auto& pair : m) {                 // C++11方式
    cout << pair.first << ": " << pair.second << endl;
}

// 删除元素
m.erase("Alice");
m.erase(it);

// 自定义比较函数
map<string, int, greater<string>> m2;        // 按键降序排列
  • multimap(多重映射):存储了键值对(pair),其中键是唯一的,但值可以重复,允许一个键映射到多个值。
#include <map>

multimap<string, int> mm = {
    {"Alice", 25},
    {"Alice", 26},
    {"Bob", 30}
};

// 允许重复键
mm.insert({"Alice", 27});

// 查找特定键的所有值
auto range = mm.equal_range("Alice");
for (auto it = range.first; it != range.second; ++it) {
    cout << it->first << ": " << it->second << endl;
}

// 应用场景:一对多映射关系

1.3无序关联式容器(哈希容器,C++11引入)

元素基于哈希表组织,不保证顺序。支持快速的查找、插入和删除。
-unordered_set(无序集合)

#include <unordered_set>

unordered_set<int> us = {5, 3, 1, 4, 2};  // 顺序不确定

// 基本操作
us.insert(6);
us.erase(3);
auto it = us.find(4);                     // 平均O(1)

// 哈希表特性
cout << "桶数量: " << us.bucket_count() << endl;
cout << "负载因子: " << us.load_factor() << endl;
cout << "最大负载因子: " << us.max_load_factor() << endl;

// 重新哈希
us.rehash(100);                           // 设置桶数量
us.reserve(100);                          // 预留空间

// 遍历桶
for (size_t i = 0; i < us.bucket_count(); ++i) {
    cout << "桶" << i << "有" << us.bucket_size(i) << "个元素" << endl;
}

// 自定义哈希函数
struct Person {
    string name;
    int age;
};

struct PersonHash {
    size_t operator()(const Person& p) const {
        return hash<string>()(p.name) ^ (hash<int>()(p.age) << 1);
    }
};

struct PersonEqual {
    bool operator()(const Person& a, const Person& b) const {
        return a.name == b.name && a.age == b.age;
    }
};

unordered_set<Person, PersonHash, PersonEqual> people;
  • unordered_map(无序映射)
#include <unordered_map>

unordered_map<string, int> um = {
    {"Alice", 25},
    {"Bob", 30},
    {"Charlie", 35}
};

// 操作类似map,但无序
um["David"] = 40;
um.insert({"Eve", 45});

// 性能相关
um.max_load_factor(0.7f);                 // 设置最大负载因子
um.rehash(50);                            // 重新哈希

// 遍历
for (const auto& [key, value] : um) {
    cout << key << ": " << value << endl;
}

// 应用场景:需要快速查找,不关心顺序

1.4 容器适配器

基于其他容器实现特殊接口。

  • stack(栈):后进先出(LIFO)的数据结构
#include <stack>

stack<int> stk;

// 基本操作
stk.push(10);
stk.push(20);
stk.push(30);

cout << "栈顶: " << stk.top() << endl;    // 30
stk.pop();                                 // 删除30
cout << "大小: " << stk.size() << endl;   // 2
cout << "是否为空: " << stk.empty() << endl; // false

// 使用不同底层容器
stack<int, vector<int>> stk_vec;          // 使用vector作为底层
stack<int, list<int>> stk_list;           // 使用list作为底层
stack<int, deque<int>> stk_deque;         // 使用deque作为底层(默认)

// 注意:stack没有迭代器,只能访问栈顶
  • queue(队列):先进先出(FIFO)的数据结构
#include <queue>

queue<int> q;

// 基本操作
q.push(10);
q.push(20);
q.push(30);

cout << "队首: " << q.front() << endl;    // 10
cout << "队尾: " << q.back() << endl;     // 30
q.pop();                                   // 删除10
cout << "大小: " << q.size() << endl;     // 2

// 使用不同底层容器
queue<int, list<int>> q_list;             // 使用list作为底层
queue<int, deque<int>> q_deque;           // 使用deque作为底层(默认)

// 注意:queue没有迭代器
  • priority_queue(优先队列):元素按优先级出队,默认最大元素优先
#include <queue>

// 默认最大堆(最大元素在顶部)
priority_queue<int> pq_max;
pq_max.push(30);
pq_max.push(10);
pq_max.push(20);
cout << "顶部: " << pq_max.top() << endl;  // 30

// 最小堆
priority_queue<int, vector<int>, greater<int>> pq_min;
pq_min.push(30);
pq_min.push(10);
pq_min.push(20);
cout << "顶部: " << pq_min.top() << endl;  // 10

// 自定义比较函数
struct Compare {
    bool operator()(int a, int b) {
        // 按绝对值比较,绝对值大的优先级高
        return abs(a) < abs(b);
    }
};
priority_queue<int, vector<int>, Compare> pq_custom;

// 存储复杂类型
struct Task {
    int priority;
    string description;
    
    bool operator<(const Task& other) const {
        return priority < other.priority;  // 最大堆
    }
};

priority_queue<Task> task_queue;
task_queue.push({3, "低优先级任务"});
task_queue.push({1, "高优先级任务"});
task_queue.push({2, "中优先级任务"});

while (!task_queue.empty()) {
    Task task = task_queue.top();
    cout << task.priority << ": " << task.description << endl;
    task_queue.pop();
}

2.算法(Algorithms)

  • STL算法是STL中非常重要的一部分,它们提供了大量的标准算法,用于对容器中的元素进行操作。这些算法覆盖了常见的操作,如查找、排序、复制、修改等。STL算法通过迭代器与容器进行交互,因此它们可以用于不同类型的容器,只需要指定要操作的范围即可。

  • STL算法的特点
    通过迭代器操作,与容器解耦
    大多数算法在<algorithm>头文件中
    数值算法在 <numeric>头文件中

  • STL算法大致可以分为以下几类:

非修改序列算法:不会改变容器中的内容,例如查找、计数等。
修改序列算法:会改变容器中的内容,例如复制、替换、填充等。
排序和相关算法:包括排序、合并、二分查找等。
数值算法:例如累加、内积等。

2.1. 非修改序列算法

  • 查找算法
#include <algorithm>
#include <vector>
#include <iostream>

void find_examples() {
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    
    // find: 查找指定值
    auto it1 = std::find(v.begin(), v.end(), 5);
    if (it1 != v.end()) {
        std::cout << "找到5: " << *it1 << std::endl;  // 5
    }
    
    // find_if: 按条件查找
    auto it2 = std::find_if(v.begin(), v.end(), [](int x) {
        return x > 7;
    });
    if (it2 != v.end()) {
        std::cout << "找到大于7的元素: " << *it2 << std::endl;  // 8
    }
    
    // find_if_not: 查找不满足条件的元素
    auto it3 = std::find_if_not(v.begin(), v.end(), [](int x) {
        return x < 5;
    });
    if (it3 != v.end()) {
        std::cout << "找到不小于5的元素: " << *it3 << std::endl;  // 5
    }
    
    // find_end: 查找子序列最后出现的位置
    std::vector<int> sub = {3, 4, 5};
    auto it4 = std::find_end(v.begin(), v.end(), sub.begin(), sub.end());
    if (it4 != v.end()) {
        std::cout << "子序列最后出现在位置: " << std::distance(v.begin(), it4) << std::endl;
    }
    
    // search: 查找子序列首次出现的位置
    auto it5 = std::search(v.begin(), v.end(), sub.begin(), sub.end());
    if (it5 != v.end()) {
        std::cout << "子序列首次出现在位置: " << std::distance(v.begin(), it5) << std::endl;
    }
    
    // search_n: 查找连续n个相同元素
    std::vector<int> v2 = {1, 2, 2, 2, 3, 4, 2, 2};
    auto it6 = std::search_n(v2.begin(), v2.end(), 3, 2);
    if (it6 != v2.end()) {
        std::cout << "找到3个连续的2" << std::endl;
    }
    
    // adjacent_find: 查找相邻重复元素
    std::vector<int> v3 = {1, 2, 3, 3, 4, 5, 5, 6};
    auto it7 = std::adjacent_find(v3.begin(), v3.end());
    if (it7 != v3.end()) {
        std::cout << "找到相邻重复元素: " << *it7 << std::endl;  // 3
    }
    
    // 自定义比较函数的adjacent_find
    auto it8 = std::adjacent_find(v3.begin(), v3.end(), 
        [](int a, int b) { return abs(a - b) == 1; });
    if (it8 != v3.end()) {
        std::cout << "找到相邻元素差为1: " << *it8 << "和" << *(it8 + 1) << std::endl;
    }
}
  • 计数算法
void count_examples() {
    std::vector<int> v = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4};
    
    // count: 统计等于某个值的元素个数
    int cnt1 = std::count(v.begin(), v.end(), 3);
    std::cout << "3的个数: " << cnt1 << std::endl;  // 3
    
    // count_if: 统计满足条件的元素个数
    int cnt2 = std::count_if(v.begin(), v.end(), [](int x) {
        return x > 2;
    });
    std::cout << "大于2的个数: " << cnt2 << std::endl;  // 7
    
    // 统计字符串中字符个数
    std::string str = "Hello, World!";
    int cnt3 = std::count(str.begin(), str.end(), 'l');
    std::cout << "l的个数: " << cnt3 << std::endl;  // 3
    
    // 统计元音字母个数
    std::string vowels = "aeiouAEIOU";
    int cnt4 = std::count_if(str.begin(), str.end(), [&vowels](char c) {
        return vowels.find(c) != std::string::npos;
    });
    std::cout << "元音字母个数: " << cnt4 << std::endl;  // 3
}
  • 比较算法
void compare_examples() {
    std::vector<int> v1 = {1, 2, 3, 4, 5};
    std::vector<int> v2 = {1, 2, 3, 4, 5};
    std::vector<int> v3 = {1, 2, 3, 4, 6};
    
    // equal: 比较两个序列是否相等
    bool eq1 = std::equal(v1.begin(), v1.end(), v2.begin());
    std::cout << "v1等于v2: " << eq1 << std::endl;  // true
    
    bool eq2 = std::equal(v1.begin(), v1.end(), v3.begin());
    std::cout << "v1等于v3: " << eq2 << std::endl;  // false
    
    // 自定义比较函数
    bool eq3 = std::equal(v1.begin(), v1.end(), v3.begin(), [](int a, int b) {
        return abs(a - b) <= 1;
    });
    std::cout << "v1与v3元素差不大于1: " << eq3 << std::endl;  // true
    
    // mismatch: 查找第一个不匹配的位置
    auto p = std::mismatch(v1.begin(), v1.end(), v3.begin());
    if (p.first != v1.end()) {
        std::cout << "第一个不匹配: " << *(p.first) << " vs " << *(p.second) << std::endl;  // 5 vs 6
    }
    
    // lexicographical_compare: 字典序比较
    std::string s1 = "apple";
    std::string s2 = "banana";
    bool lt = std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end());
    std::cout << s1 << " < " << s2 << ": " << lt << std::endl;  // true
    
    // is_permutation: 判断是否为排列(C++11)
    std::vector<int> v4 = {1, 2, 3, 4, 5};
    std::vector<int> v5 = {5, 4, 3, 2, 1};
    bool perm = std::is_permutation(v4.begin(), v4.end(), v5.begin());
    std::cout << "v5是v4的排列: " << perm << std::endl;  // true
}
  • 遍历算法
#include <algorithm>
#include <vector>
#include <iostream>
#include <functional>

void foreach_examples() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    // for_each: 对每个元素执行操作
    std::cout << "原始值: ";
    std::for_each(v.begin(), v.end(), [](int x) {
        std::cout << x << " ";
    });
    std::cout << std::endl;
    
    // 修改元素
    std::cout << "乘以2: ";
    std::for_each(v.begin(), v.end(), [](int& x) {
        x *= 2;
    });
    std::for_each(v.begin(), v.end(), [](int x) {
        std::cout << x << " ";
    });
    std::cout << std::endl;
    
    // 使用函数对象
    struct Printer {
        void operator()(int x) const {
            std::cout << x << " ";
        }
    };
    std::cout << "使用函数对象: ";
    std::for_each(v.begin(), v.end(), Printer());
    std::cout << std::endl;
    
    // for_each_n: 对前n个元素执行操作(C++17)
    std::vector<int> v2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::cout << "前5个元素加10: ";
    std::for_each_n(v2.begin(), 5, [](int& x) { x += 10; });
    for (int x : v2) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    // 统计操作次数
    struct Counter {
        int count = 0;
        void operator()(int x) {
            if (x > 12) ++count;
        }
    };
    
    Counter c = std::for_each(v2.begin(), v2.end(), Counter());
    std::cout << "大于12的元素个数: " << c.count << std::endl;
}
  • 搜索算法
void search_examples() {
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    
    // lower_bound: 第一个不小于给定值的迭代器
    auto lb = std::lower_bound(v.begin(), v.end(), 5);
    std::cout << "第一个不小于5的元素: " << *lb << std::endl;  // 5
    
    // upper_bound: 第一个大于给定值的迭代器
    auto ub = std::upper_bound(v.begin(), v.end(), 5);
    std::cout << "第一个大于5的元素: " << *ub << std::endl;  // 6
    
    // equal_range: 返回等于给定值的范围
    auto range = std::equal_range(v.begin(), v.end(), 5);
    std::cout << "等于5的范围: [" << std::distance(v.begin(), range.first) 
              << ", " << std::distance(v.begin(), range.second) << ")" << std::endl;
    
    // binary_search: 判断是否存在(要求序列有序)
    bool found = std::binary_search(v.begin(), v.end(), 5);
    std::cout << "5是否存在: " << found << std::endl;  // true
}

2.2. 修改序列算法

  • 复制算法
void copy_examples() {
    std::vector<int> src = {1, 2, 3, 4, 5};
    
    // copy: 复制元素
    std::vector<int> dst1(src.size());
    std::copy(src.begin(), src.end(), dst1.begin());
    std::cout << "copy结果: ";
    for (int x : dst1) std::cout << x << " ";
    std::cout << std::endl;
    
    // copy_if: 按条件复制
    std::vector<int> dst2;
    std::copy_if(src.begin(), src.end(), std::back_inserter(dst2),
                 [](int x) { return x % 2 == 0; });
    std::cout << "copy_if(偶数): ";
    for (int x : dst2) std::cout << x << " ";
    std::cout << std::endl;
    
    // copy_n: 复制前n个元素
    std::vector<int> dst3(3);
    std::copy_n(src.begin(), 3, dst3.begin());
    std::cout << "copy_n(前3个): ";
    for (int x : dst3) std::cout << x << " ";
    std::cout << std::endl;
    
    // copy_backward: 从后往前复制
    std::vector<int> dst4(5);
    std::copy_backward(src.begin(), src.end(), dst4.end());
    std::cout << "copy_backward结果: ";
    for (int x : dst4) std::cout << x << " ";
    std::cout << std::endl;
    
    // 复制到输出流
    std::cout << "复制到输出流: ";
    std::copy(src.begin(), src.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
    
    // 从输入流复制
    std::istringstream iss("1 2 3 4 5");
    std::vector<int> dst5;
    std::copy(std::istream_iterator<int>(iss),
              std::istream_iterator<int>(),
              std::back_inserter(dst5));
    std::cout << "从输入流复制: ";
    for (int x : dst5) std::cout << x << " ";
    std::cout << std::endl;
}
  • 移动算法
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>

void move_examples() {
    // move: 移动元素(C++11)
    std::vector<std::string> src = {"apple", "banana", "cherry"};
    std::vector<std::string> dst(3);
    
    std::cout << "move前src: ";
    for (const auto& s : src) std::cout << "\"" << s << "\" ";
    std::cout << std::endl;
    
    std::move(src.begin(), src.end(), dst.begin());
    
    std::cout << "move后src: ";
    for (const auto& s : src) std::cout << "\"" << s << "\" ";  // 有效但未指定状态
    std::cout << std::endl;
    
    std::cout << "move后dst: ";
    for (const auto& s : dst) std::cout << "\"" << s << "\" ";
    std::cout << std::endl;
    
    // move_backward: 从后往前移动
    std::vector<std::string> src2 = {"dog", "cat", "bird"};
    std::vector<std::string> dst2(5);
    
    std::move_backward(src2.begin(), src2.end(), dst2.end());
    
    std::cout << "move_backward后dst2: ";
    for (const auto& s : dst2) {
        if (s.empty()) std::cout << "[空] ";
        else std::cout << "\"" << s << "\" ";
    }
    std::cout << std::endl;
    
    // 实际应用:交换两个vector
    std::vector<int> v1 = {1, 2, 3};
    std::vector<int> v2 = {4, 5, 6};
    
    std::cout << "交换前 v1: ";
    for (int x : v1) std::cout << x << " ";
    std::cout << "\n交换前 v2: ";
    for (int x : v2) std::cout << x << " ";
    std::cout << std::endl;
    
    // 使用move交换
    std::vector<int> temp = std::move(v1);
    v1 = std::move(v2);
    v2 = std::move(temp);
    
    std::cout << "交换后 v1: ";
    for (int x : v1) std::cout << x << " ";
    std::cout << "\n交换后 v2: ";
    for (int x : v2) std::cout << x << " ";
    std::cout << std::endl;
}
  • 变换算法
void transform_examples() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    // transform: 对每个元素应用函数
    std::vector<int> result(v.size());
    std::transform(v.begin(), v.end(), result.begin(),
                   [](int x) { return x * x; });
    
    std::cout << "平方变换: ";
    for (int x : result) std::cout << x << " ";
    std::cout << std::endl;
    
    // 两个序列的transform
    std::vector<int> v1 = {1, 2, 3};
    std::vector<int> v2 = {4, 5, 6};
    std::vector<int> result2(v1.size());
    
    std::transform(v1.begin(), v1.end(), v2.begin(), result2.begin(),
                   [](int a, int b) { return a + b; });
    
    std::cout << "两个序列相加: ";
    for (int x : result2) std::cout << x << " ";
    std::cout << std::endl;
    
    // 原地变换
    std::cout << "原地乘以2: ";
    std::transform(v.begin(), v.end(), v.begin(),
                   [](int x) { return x * 2; });
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // 字符串变换
    std::string str = "Hello World";
    std::string upper_str;
    std::transform(str.begin(), str.end(), std::back_inserter(upper_str),
                   [](char c) { return std::toupper(c); });
    
    std::cout << "转大写: " << upper_str << std::endl;
    
    // 复杂变换:生成斐波那契数列
    std::vector<int> fib(10);
    fib[0] = 0;
    fib[1] = 1;
    
    std::transform(fib.begin(), fib.end() - 2,
                   fib.begin() + 1,
                   fib.begin() + 2,
                   std::plus<int>());
    
    std::cout << "斐波那契数列: ";
    for (int x : fib) std::cout << x << " ";
    std::cout << std::endl;
}
  • 替换算法
void replace_examples() {
    std::vector<int> v = {1, 2, 3, 2, 5, 2, 7};
    
    // replace: 替换指定值
    std::replace(v.begin(), v.end(), 2, 99);
    std::cout << "替换2为99: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // replace_if: 按条件替换
    std::vector<int> v2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::replace_if(v2.begin(), v2.end(),
                    [](int x) { return x < 5; },
                    0);
    std::cout << "替换小于5的为0: ";
    for (int x : v2) std::cout << x << " ";
    std::cout << std::endl;
    
    // replace_copy: 替换并复制到新容器
    std::vector<int> src = {1, 2, 3, 2, 5};
    std::vector<int> dst(src.size());
    std::replace_copy(src.begin(), src.end(), dst.begin(), 2, 99);
    
    std::cout << "原始: ";
    for (int x : src) std::cout << x << " ";
    std::cout << "\n替换复制后: ";
    for (int x : dst) std::cout << x << " ";
    std::cout << std::endl;
    
    // replace_copy_if: 按条件替换并复制
    std::vector<int> dst2(src.size());
    std::replace_copy_if(src.begin(), src.end(), dst2.begin(),
                         [](int x) { return x % 2 == 0; },
                         -1);
    
    std::cout << "替换偶数为-1并复制: ";
    for (int x : dst2) std::cout << x << " ";
    std::cout << std::endl;
}
  • 填充算法
void fill_examples() {
    // fill: 填充值
    std::vector<int> v(5);
    std::fill(v.begin(), v.end(), 42);
    std::cout << "填充42: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // fill_n: 填充前n个元素
    std::vector<int> v2(10);
    std::fill_n(v2.begin(), 3, 99);
    std::cout << "填充前3个为99: ";
    for (int x : v2) std::cout << x << " ";
    std::cout << std::endl;
    
    // generate: 用函数生成值
    std::vector<int> v3(5);
    int n = 1;
    std::generate(v3.begin(), v3.end(), [&n]() { return n++; });
    std::cout << "生成递增序列: ";
    for (int x : v3) std::cout << x << " ";
    std::cout << std::endl;
    
    // generate_n: 生成前n个值
    std::vector<int> v4(5);
    std::generate_n(v4.begin(), 3, []() { return rand() % 100; });
    std::cout << "生成前3个随机数: ";
    for (int x : v4) std::cout << x << " ";
    std::cout << std::endl;
    
    // iota: 填充递增序列(C++11)
    std::vector<int> v5(10);
    std::iota(v5.begin(), v5.end(), 100);
    std::cout << "iota从100开始: ";
    for (int x : v5) std::cout << x << " ";
    std::cout << std::endl;
}
  • 删除算法
void remove_examples() {
    // remove: 逻辑删除指定值
    std::vector<int> v = {1, 2, 3, 2, 5, 2, 7};
    auto new_end = std::remove(v.begin(), v.end(), 2);
    
    std::cout << "逻辑删除2后: ";
    for (auto it = v.begin(); it != new_end; ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    std::cout << "整个vector: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // 物理删除
    v.erase(new_end, v.end());
    std::cout << "物理删除后: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // remove_if: 按条件删除
    v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    new_end = std::remove_if(v.begin(), v.end(),
                             [](int x) { return x % 2 == 0; });
    v.erase(new_end, v.end());
    std::cout << "删除偶数后: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // remove_copy: 删除并复制到新容器
    std::vector<int> src = {1, 2, 3, 2, 5};
    std::vector<int> dst;
    std::remove_copy(src.begin(), src.end(), std::back_inserter(dst), 2);
    std::cout << "删除2并复制: ";
    for (int x : dst) std::cout << x << " ";
    std::cout << std::endl;
    
    // unique: 删除相邻重复元素
    std::vector<int> v2 = {1, 1, 2, 2, 3, 3, 3, 4, 5, 5};
    new_end = std::unique(v2.begin(), v2.end());
    v2.erase(new_end, v2.end());
    std::cout << "去重后: ";
    for (int x : v2) std::cout << x << " ";
    std::cout << std::endl;
    
    // 自定义相等判断的unique
    std::vector<int> v3 = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
    std::sort(v3.begin(), v3.end());
    new_end = std::unique(v3.begin(), v3.end(),
                          [](int a, int b) { return abs(a - b) <= 1; });
    v3.erase(new_end, v3.end());
    std::cout << "自定义去重(差<=1): ";
    for (int x : v3) std::cout << x << " ";
    std::cout << std::endl;
}
  • 交换算法
void swap_examples() {
    // swap: 交换两个元素
    int a = 10, b = 20;
    std::swap(a, b);
    std::cout << "a = " << a << ", b = " << b << std::endl;  // a=20, b=10
    
    // swap_ranges: 交换两个范围
    std::vector<int> v1 = {1, 2, 3, 4, 5};
    std::vector<int> v2 = {10, 20, 30, 40, 50};
    
    std::swap_ranges(v1.begin(), v1.begin() + 3, v2.begin());
    
    std::cout << "交换范围后v1: ";
    for (int x : v1) std::cout << x << " ";
    std::cout << "\n交换范围后v2: ";
    for (int x : v2) std::cout << x << " ";
    std::cout << std::endl;
    
    // iter_swap: 交换两个迭代器指向的元素
    std::vector<int> v3 = {1, 2, 3, 4, 5};
    std::iter_swap(v3.begin(), v3.end() - 1);
    std::cout << "交换首尾后v3: ";
    for (int x : v3) std::cout << x << " ";
    std::cout << std::endl;
    
    // 交换整个容器
    std::vector<int> v4 = {1, 2, 3};
    std::vector<int> v5 = {4, 5, 6};
    std::swap(v4, v5);
    
    std::cout << "交换容器后v4: ";
    for (int x : v4) std::cout << x << " ";
    std::cout << "\n交换容器后v5: ";
    for (int x : v5) std::cout << x << " ";
    std::cout << std::endl;
}

2.3. 排序和相关算法

  • 排序算法
void sort_examples() {
    std::vector<int> v = {5, 3, 1, 4, 2, 6, 8, 7, 9};
    
    // sort: 快速排序
    std::sort(v.begin(), v.end());
    std::cout << "升序排序: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // 降序排序
    std::sort(v.begin(), v.end(), std::greater<int>());
    std::cout << "降序排序: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // 自定义排序
    std::vector<std::string> words = {"apple", "banana", "cherry", "date"};
    std::sort(words.begin(), words.end(),
              [](const std::string& a, const std::string& b) {
                  return a.length() < b.length();
              });
    std::cout << "按长度排序: ";
    for (const auto& w : words) std::cout << w << " ";
    std::cout << std::endl;
    
    // stable_sort: 稳定排序
    std::vector<std::pair<int, int>> pairs = {
        {1, 5}, {2, 3}, {1, 3}, {2, 1}, {1, 1}
    };
    std::stable_sort(pairs.begin(), pairs.end(),
                     [](const auto& a, const auto& b) {
                         return a.first < b.first;
                     });
    std::cout << "稳定排序(按first): ";
    for (const auto& p : pairs) {
        std::cout << "(" << p.first << "," << p.second << ") ";
    }
    std::cout << std::endl;
    
    // partial_sort: 部分排序
    v = {5, 3, 1, 4, 2, 6, 8, 7, 9};
    std::partial_sort(v.begin(), v.begin() + 3, v.end());
    std::cout << "部分排序(前3个最小): ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // nth_element: 使第n个元素处于正确位置
    v = {5, 3, 1, 4, 2, 6, 8, 7, 9};
    std::nth_element(v.begin(), v.begin() + 4, v.end());
    std::cout << "第5小元素是: " << v[4] << std::endl;
    std::cout << "nth_element后: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // is_sorted: 判断是否有序
    v = {1, 2, 3, 4, 5};
    bool sorted = std::is_sorted(v.begin(), v.end());
    std::cout << "是否升序: " << sorted << std::endl;  // true
    
    // is_sorted_until: 查找无序位置
    v = {1, 2, 3, 5, 4, 6, 7};
    auto it = std::is_sorted_until(v.begin(), v.end());
    if (it != v.end()) {
        std::cout << "从位置 " << std::distance(v.begin(), it)
                  << " 开始无序" << std::endl;
    }
}
  • 二分查找算法
void binary_search_examples() {
    // 必须是有序序列
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    
    // binary_search: 判断是否存在
    bool found = std::binary_search(v.begin(), v.end(), 5);
    std::cout << "5是否存在: " << found << std::endl;  // true
    
    found = std::binary_search(v.begin(), v.end(), 10);
    std::cout << "10是否存在: " << found << std::endl;  // false
    
    // lower_bound: 第一个不小于给定值的迭代器
    auto lb = std::lower_bound(v.begin(), v.end(), 5);
    std::cout << "第一个不小于5的元素: " << *lb << std::endl;  // 5
    
    lb = std::lower_bound(v.begin(), v.end(), 5.5);
    std::cout << "第一个不小于5.5的元素: " << *lb << std::endl;  // 6
    
    // upper_bound: 第一个大于给定值的迭代器
    auto ub = std::upper_bound(v.begin(), v.end(), 5);
    std::cout << "第一个大于5的元素: " << *ub << std::endl;  // 6
    
    // equal_range: 返回等于给定值的范围
    auto range = std::equal_range(v.begin(), v.end(), 5);
    std::cout << "等于5的范围大小: " 
              << std::distance(range.first, range.second) << std::endl;  // 1
    
    // 在自定义排序的序列中查找
    std::vector<int> v2 = {9, 8, 7, 6, 5, 4, 3, 2, 1};  // 降序
    found = std::binary_search(v2.begin(), v2.end(), 5, std::greater<int>());
    std::cout << "在降序序列中5是否存在: " << found << std::endl;  // true
    
    // 查找第一个大于等于3的元素(在降序序列中)
    lb = std::lower_bound(v2.begin(), v2.end(), 3, std::greater<int>());
    std::cout << "降序序列中第一个>=3的元素: " << *lb << std::endl;  // 3
    
    // 应用:查找区间
    struct Interval {
        int start, end;
        bool operator<(const Interval& other) const {
            return start < other.start;
        }
    };
    
    std::vector<Interval> intervals = {
        {1, 3}, {2, 4}, {5, 7}, {6, 8}
    };
    
    // 查找起点大于等于3的区间
    Interval target = {3, 0};
    auto it = std::lower_bound(intervals.begin(), intervals.end(), target);
    if (it != intervals.end()) {
        std::cout << "第一个起点>=3的区间: [" 
                  << it->start << ", " << it->end << "]" << std::endl;
    }
}
  • 合并算法
void merge_examples() {
    // merge: 合并两个有序序列
    std::vector<int> v1 = {1, 3, 5, 7, 9};
    std::vector<int> v2 = {2, 4, 6, 8, 10};
    std::vector<int> result(v1.size() + v2.size());
    
    std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());
    
    std::cout << "合并结果: ";
    for (int x : result) std::cout << x << " ";
    std::cout << std::endl;
    
    // 自定义比较函数的merge
    std::vector<int> v3 = {9, 7, 5, 3, 1};  // 降序
    std::vector<int> v4 = {10, 8, 6, 4, 2}; // 降序
    std::vector<int> result2(v3.size() + v4.size());
    
    std::merge(v3.begin(), v3.end(), v4.begin(), v4.end(),
               result2.begin(), std::greater<int>());
    
    std::cout << "降序合并: ";
    for (int x : result2) std::cout << x << " ";
    std::cout << std::endl;
    
    // inplace_merge: 原地合并
    std::vector<int> v5 = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
    std::inplace_merge(v5.begin(), v5.begin() + 5, v5.end());
    
    std::cout << "原地合并: ";
    for (int x : v5) std::cout << x << " ";
    std::cout << std::endl;
    
    // 应用:多路归并
    std::vector<std::vector<int>> vectors = {
        {1, 4, 7},
        {2, 5, 8},
        {3, 6, 9}
    };
    
    std::vector<int> merged;
    for (const auto& vec : vectors) {
        std::vector<int> temp(merged.size() + vec.size());
        std::merge(merged.begin(), merged.end(), vec.begin(), vec.end(),
                   temp.begin());
        merged.swap(temp);
    }
    
    std::cout << "多路归并: ";
    for (int x : merged) std::cout << x << " ";
    std::cout << std::endl;
}
  • 集合算法
void set_algorithm_examples() {
    // 要求序列有序
    std::vector<int> v1 = {1, 2, 3, 4, 5};
    std::vector<int> v2 = {3, 4, 5, 6, 7};
    std::vector<int> result;
    
    // set_union: 并集
    std::set_union(v1.begin(), v1.end(),
                   v2.begin(), v2.end(),
                   std::back_inserter(result));
    std::cout << "并集: ";
    for (int x : result) std::cout << x << " ";
    std::cout << std::endl;
    
    // set_intersection: 交集
    result.clear();
    std::set_intersection(v1.begin(), v1.end(),
                          v2.begin(), v2.end(),
                          std::back_inserter(result));
    std::cout << "交集: ";
    for (int x : result) std::cout << x << " ";
    std::cout << std::endl;
    
    // set_difference: 差集 (v1 - v2)
    result.clear();
    std::set_difference(v1.begin(), v1.end(),
                        v2.begin(), v2.end(),
                        std::back_inserter(result));
    std::cout << "差集(v1-v2): ";
    for (int x : result) std::cout << x << " ";
    std::cout << std::endl;
    
    // set_symmetric_difference: 对称差集
    result.clear();
    std::set_symmetric_difference(v1.begin(), v1.end(),
                                  v2.begin(), v2.end(),
                                  std::back_inserter(result));
    std::cout << "对称差集: ";
    for (int x : result) std::cout << x << " ";
    std::cout << std::endl;
    
    // includes: 判断是否包含
    bool includes = std::includes(v1.begin(), v1.end(),
                                  v2.begin(), v2.begin() + 3);  // {3, 4, 5}
    std::cout << "v1是否包含{3,4,5}: " << includes << std::endl;  // true
    
    // 应用:合并多个集合
    std::vector<std::vector<int>> sets = {
        {1, 2, 3},
        {2, 3, 4},
        {3, 4, 5}
    };
    
    std::vector<int> all_elements;
    for (const auto& s : sets) {
        std::vector<int> temp;
        std::set_union(all_elements.begin(), all_elements.end(),
                       s.begin(), s.end(),
                       std::back_inserter(temp));
        all_elements.swap(temp);
    }
    
    std::cout << "所有集合的元素: ";
    for (int x : all_elements) std::cout << x << " ";
    std::cout << std::endl;
}
  • 堆算法
void heap_examples() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
    
    // make_heap: 建立最大堆
    std::make_heap(v.begin(), v.end());
    std::cout << "最大堆: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    std::cout << "堆顶: " << v.front() << std::endl;  // 9
    
    // push_heap: 添加元素到堆
    v.push_back(8);
    std::push_heap(v.begin(), v.end());
    std::cout << "添加8后: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // pop_heap: 从堆中移除最大元素
    std::pop_heap(v.begin(), v.end());
    int max_val = v.back();
    v.pop_back();
    std::cout << "移除最大元素: " << max_val << std::endl;
    std::cout << "剩余堆: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // sort_heap: 堆排序
    std::sort_heap(v.begin(), v.end());
    std::cout << "堆排序后: ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    // is_heap: 判断是否为堆
    std::vector<int> v2 = {9, 5, 4, 1, 3, 2};
    bool is_heap = std::is_heap(v2.begin(), v2.end());
    std::cout << "是否为堆: " << is_heap << std::endl;  // false
    
    std::make_heap(v2.begin(), v2.end());
    is_heap = std::is_heap(v2.begin(), v2.end());
    std::cout << "建立堆后是否为堆: " << is_heap << std::endl;  // true
    
    // is_heap_until: 查找破坏堆性质的位置
    v2.push_back(10);
    auto it = std::is_heap_until(v2.begin(), v2.end());
    std::cout << "破坏堆性质的位置: " << std::distance(v2.begin(), it)
              << " (元素: " << *it << ")" << std::endl;
    
    // 最小堆
    std::vector<int> v3 = {5, 3, 8, 1, 9};
    std::make_heap(v3.begin(), v3.end(), std::greater<int>());
    std::cout << "最小堆: ";
    for (int x : v3) std::cout << x << " ";
    std::cout << "\n最小堆堆顶: " << v3.front() << std::endl;  // 1
    
    // 应用:优先级队列
    std::vector<int> tasks = {3, 1, 4, 1, 5, 9, 2, 6};
    std::make_heap(tasks.begin(), tasks.end(), std::greater<int>());  // 最小堆
    
    std::cout << "处理任务顺序: ";
    while (!tasks.empty()) {
        std::pop_heap(tasks.begin(), tasks.end(), std::greater<int>());
        int task = tasks.back();
        tasks.pop_back();
        std::cout << task << " ";
    }
    std::cout << std::endl;
}
  • 最值算法
void minmax_examples() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
    
    // min: 返回最小值
    int m1 = std::min(10, 20);
    std::cout << "min(10, 20) = " << m1 << std::endl;  // 10
    
    // max: 返回最大值
    int m2 = std::max(10, 20);
    std::cout << "max(10, 20) = " << m2 << std::endl;  // 20
    
    // minmax: 返回最小值和最大值(C++11)
    auto mm1 = std::minmax(10, 20);
    std::cout << "minmax(10, 20) = (" << mm1.first << ", " << mm1.second << ")" << std::endl;
    
    // min_element: 返回最小元素的迭代器
    auto min_it = std::min_element(v.begin(), v.end());
    std::cout << "最小元素: " << *min_it << " 位置: " 
              << std::distance(v.begin(), min_it) << std::endl;
    
    // max_element: 返回最大元素的迭代器
    auto max_it = std::max_element(v.begin(), v.end());
    std::cout << "最大元素: " << *max_it << " 位置: "
              << std::distance(v.begin(), max_it) << std::endl;
    
    // minmax_element: 返回最小和最大元素的迭代器(C++11)
    auto mm_it = std::minmax_element(v.begin(), v.end());
    std::cout << "最小元素: " << *(mm_it.first) 
              << " 最大元素: " << *(mm_it.second) << std::endl;
    
    // 自定义比较函数
    std::vector<std::string> words = {"apple", "banana", "cherry", "date"};
    auto longest = std::max_element(words.begin(), words.end(),
                                    [](const std::string& a, const std::string& b) {
                                        return a.length() < b.length();
                                    });
    std::cout << "最长的单词: " << *longest << std::endl;
    
    // clamp: 限制值在范围内(C++17)
    int value = 150;
    int clamped = std::clamp(value, 0, 100);
    std::cout << "clamp(150, 0, 100) = " << clamped << std::endl;  // 100
    
    // 应用:查找成绩最优和最差的学生
    struct Student {
        std::string name;
        int score;
    };
    
    std::vector<Student> students = {
        {"Alice", 85},
        {"Bob", 92},
        {"Charlie", 78},
        {"David", 95},
        {"Eve", 88}
    };
    
    auto best = std::max_element(students.begin(), students.end(),
                                 [](const Student& a, const Student& b) {
                                     return a.score < b.score;
                                 });
    auto worst = std::min_element(students.begin(), students.end(),
                                  [](const Student& a, const Student& b) {
                                      return a.score < b.score;
                                  });
    
    std::cout << "最高分: " << best->name << " (" << best->score << "分)" << std::endl;
    std::cout << "最低分: " << worst->name << " (" << worst->score << "分)" << std::endl;
}
  • 排列算法
void permutation_examples() {
    std::vector<int> v = {1, 2, 3};
    
    std::cout << "所有排列:\n";
    do {
        for (int x : v) std::cout << x << " ";
        std::cout << std::endl;
    } while (std::next_permutation(v.begin(), v.end()));
    
    // 重新初始化为降序
    v = {3, 2, 1};
    std::cout << "\n降序排列的上一个排列:\n";
    std::prev_permutation(v.begin(), v.end());
    for (int x : v) std::cout << x << " ";  // 3 1 2
    std::cout << std::endl;
    
    // 判断是否为排列
    std::vector<int> v1 = {1, 2, 3, 4, 5};
    std::vector<int> v2 = {5, 4, 3, 2, 1};
    bool is_perm = std::is_permutation(v1.begin(), v1.end(), v2.begin());
    std::cout << "v2是否是v1的排列: " << is_perm << std::endl;  // true
    
    // 生成所有排列的应用:解决旅行商问题(暴力搜索)
    std::vector<std::string> cities = {"A", "B", "C", "D"};
    std::sort(cities.begin(), cities.end());  // 先排序
    
    std::cout << "\n所有旅行路线:\n";
    int count = 0;
    do {
        std::cout << ++count << ": ";
        for (const auto& city : cities) {
            std::cout << city << " ";
        }
        std::cout << std::endl;
    } while (std::next_permutation(cities.begin(), cities.end()));
}

2.4. 数值算法

#include <numeric>  // 数值算法头文件
#include <iostream>
#include <vector>
#include <cmath>

void numeric_examples() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    // accumulate: 累加
    int sum = std::accumulate(v.begin(), v.end(), 0);
    std::cout << "累加: " << sum << std::endl;  // 15
    
    // 累乘
    int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
    std::cout << "累乘: " << product << std::endl;  // 120
    
    // 字符串连接
    std::vector<std::string> words = {"Hello", " ", "World", "!"};
    std::string sentence = std::accumulate(words.begin(), words.end(), std::string());
    std::cout << "字符串连接: " << sentence << std::endl;  // Hello World!
    
    // inner_product: 内积(点积)
    std::vector<int> v1 = {1, 2, 3};
    std::vector<int> v2 = {4, 5, 6};
    int dot = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0);
    std::cout << "内积: " << dot << std::endl;  // 32 (1*4 + 2*5 + 3*6)
    
    // 自定义操作的内积
    int sum_of_squares = std::inner_product(v1.begin(), v1.end(), v1.begin(), 0);
    std::cout << "平方和: " << sum_of_squares << std::endl;  // 14 (1*1 + 2*2 + 3*3)
    
    // partial_sum: 部分和
    std::vector<int> prefix_sum(v.size());
    std::partial_sum(v.begin(), v.end(), prefix_sum.begin());
    std::cout << "部分和: ";
    for (int x : prefix_sum) std::cout << x << " ";  // 1 3 6 10 15
    std::cout << std::endl;
    
    // 自定义操作的partial_sum
    std::vector<int> prefix_product(v.size());
    std::partial_sum(v.begin(), v.end(), prefix_product.begin(), std::multiplies<int>());
    std::cout << "部分积: ";
    for (int x : prefix_product) std::cout << x << " ";  // 1 2 6 24 120
    std::cout << std::endl;
    
    // adjacent_difference: 相邻差
    std::vector<int> diff(v.size());
    std::adjacent_difference(v.begin(), v.end(), diff.begin());
    std::cout << "相邻差: ";
    for (int x : diff) std::cout << x << " ";  // 1 1 1 1 1
    std::cout << std::endl;
    
    // 自定义操作的adjacent_difference
    std::vector<int> ratio(v.size());
    std::adjacent_difference(v.begin(), v.end(), ratio.begin(),
                             [](int a, int b) { return a - b; });
    std::cout << "相邻差(自定义): ";
    for (int x : ratio) std::cout << x << " ";
    std::cout << std::endl;
    
    // iota: 填充递增序列
    std::vector<int> seq(10);
    std::iota(seq.begin(), seq.end(), 100);
    std::cout << "iota从100开始: ";
    for (int x : seq) std::cout << x << " ";  // 100 101 102 ... 109
    std::cout << std::endl;
    
    // gcd和lcm(C++17)
    int a = 12, b = 18;
    int g = std::gcd(a, b);
    int l = std::lcm(a, b);
    std::cout << "gcd(12, 18) = " << g << std::endl;  // 6
    std::cout << "lcm(12, 18) = " << l << std::endl;  // 36
    
    // midpoint(C++20)
    int m = std::midpoint(10, 20);
    std::cout << "midpoint(10, 20) = " << m << std::endl;  // 15
    
    // 应用:计算加权平均值
    std::vector<double> values = {85, 90, 78, 92, 88};
    std::vector<double> weights = {0.1, 0.2, 0.3, 0.2, 0.2};
    
    double weighted_sum = std::inner_product(values.begin(), values.end(),
                                             weights.begin(), 0.0);
    double total_weight = std::accumulate(weights.begin(), weights.end(), 0.0);
    double weighted_avg = weighted_sum / total_weight;
    
    std::cout << "加权平均值: " << weighted_avg << std::endl;
}

3.迭代器(Iterators)

  • 迭代器用于遍历容器中的元素,它是一种类似指针的对象,允许以统一的方式访问容器中的元素,而不用了解容器的内部实现细节。
  • 迭代器的作用
    1.连接容器和算法
    2.提供统一的访问接口
    3.支持泛型编程

3.1. 迭代器类别

  • 五种迭代器类别

// 迭代器分类(按功能从弱到强)

  1. 输入迭代器 (Input Iterator) - 只读,只能向前移动
  2. 输出迭代器 (Output Iterator) - 只写,只能向前移动
  3. 前向迭代器 (Forward Iterator) - 可读写,只能向前移动
  4. 双向迭代器 (Bidirectional Iterator) - 可读写,可向前向后移动
  5. 随机访问迭代器 (Random Access Iterator) - 可读写,支持随机访问
  • 各类迭代器的能力矩阵
操作 输入 输出 前向 双向 随机访问
读 (*it)
写 (*it = value)
递增 (++)
递减 (–)
比较 (==, !=)
一次遍历
多次遍历
加/减整数 (it + n)
下标访问 (it[n])
比较大小 (<, >)
距离 (it1 - it2)

3.2. 迭代器使用

  • 获取迭代器
    每个容器都提供了获取迭代器的成员函数:
    begin()、end():返回指向第一个元素和尾后位置的迭代器
    cbegin()、cend():返回const迭代器(C++11引入)
    rbegin()、rend():返回反向迭代器
    crbegin()、crend():返回const反向迭代器(C++11引入)
  • 迭代器操作示例
#include <iostream>
#include <vector>
#include <list>

void basic_operations() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    // 获取迭代器
    auto begin_it = v.begin();    // 指向第一个元素
    auto end_it = v.end();        // 指向最后一个元素的下一个位置
    
    // 解引用
    int first = *begin_it;        // 获取第一个元素的值
    *begin_it = 10;               // 修改第一个元素的值
    
    // 递增
    auto it = begin_it;
    ++it;                         // 移动到下一个元素
    it++;                         // 移动到下一个元素
    
    // 比较
    if (it != end_it) {
        std::cout << "迭代器有效" << std::endl;
    }
    
    // 迭代器遍历
    for (auto it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
}
  • 不同容器的迭代器特性
void iterator_properties() {
    // vector - 随机访问迭代器
    std::vector<int> vec = {1, 2, 3, 4, 5};
    auto vec_it = vec.begin();
    vec_it += 3;                  // 支持随机访问
    int value = vec_it[2];        // 支持下标访问
    if (vec_it > vec.begin()) {   // 支持比较
        // ...
    }
    
    // list - 双向迭代器
    std::list<int> lst = {1, 2, 3, 4, 5};
    auto lst_it = lst.begin();
    ++lst_it;                     // 支持向前移动
    --lst_it;                     // 支持向后移动
    // lst_it += 2;               // 错误:不支持随机访问
    // int val = lst_it[2];       // 错误:不支持下标访问
    
    // set - 双向迭代器(const迭代器)
    std::set<int> s = {1, 2, 3, 4, 5};
    auto set_it = s.begin();
    // *set_it = 10;              // 错误:set迭代器是const的
    int read_value = *set_it;     // 只能读取
    
    // map - 双向迭代器
    std::map<std::string, int> m = {{"a", 1}, {"b", 2}};
    auto map_it = m.begin();
    map_it->first;                // 访问键(只读)
    map_it->second = 3;           // 可以修改值
}

3.3. 迭代器适配器

迭代器适配器是特殊的迭代器,它们修改或增强现有迭代器的行为。常见的迭代器适配器有:

  • 反向迭代器(Reverse Iterators):允许反向遍历容器。
std::vector<int> v = {1, 2, 3, 4, 5};
for (auto rit = v.rbegin(); rit != v.rend(); ++rit) {
    std::cout << *rit << " ";  // 输出: 5 4 3 2 1
}
  • 插入迭代器(Insert Iterators):用于将元素插入容器,而不是覆盖现有元素。
#include <iterator>
#include <vector>
#include <list>
#include <iostream>

int main() {
    std::vector<int> v = {1, 2, 3};
    std::list<int> lst;
    
    // 使用back_inserter(尾部插入)
    std::copy(v.begin(), v.end(), std::back_inserter(lst));
    // lst: 1 2 3
    
    // 使用front_inserter(头部插入)
    std::list<int> lst2;
    std::copy(v.begin(), v.end(), std::front_inserter(lst2));
    // lst2: 3 2 1(注意顺序)
    
    // 使用inserter(指定位置插入)
    std::vector<int> v2 = {4, 5, 6};
    std::copy(v2.begin(), v2.end(), std::inserter(lst, lst.begin()));
    // lst: 4 5 6 1 2 3
    
    return 0;
}
  • 流迭代器(Stream Iterators):用于从流中读取或写入数据。
#include <iterator>
#include <vector>
#include <iostream>
#include <sstream>

int main() {
    // 从标准输入读取整数
    std::cout << "请输入一些整数,以Ctrl+D结束: ";
    std::istream_iterator<int> input_begin(std::cin);
    std::istream_iterator<int> input_end;
    std::vector<int> numbers(input_begin, input_end);
    
    // 输出到标准输出
    std::cout << "你输入的数字是: ";
    std::ostream_iterator<int> output(std::cout, " ");
    std::copy(numbers.begin(), numbers.end(), output);
    std::cout << std::endl;
    
    // 从字符串流读取
    std::stringstream ss("1 2 3 4 5");
    std::istream_iterator<int> ss_begin(ss);
    std::istream_iterator<int> ss_end;
    std::vector<int> nums(ss_begin, ss_end);
    
    return 0;
}
  • 移动迭代器(Move Iterators,C++11引入):将迭代器的解引用操作转换为移动操作。
#include <iterator>
#include <vector>
#include <string>
#include <iostream>

int main() {
    std::vector<std::string> src = {"apple", "banana", "cherry"};
    std::vector<std::string> dst;
    
    // 使用移动迭代器将元素从src移动到dst
    dst.assign(std::make_move_iterator(src.begin()),
               std::make_move_iterator(src.end()));
    
    std::cout << "src: ";
    for (const auto& s : src) {
        std::cout << "\"" << s << "\" ";  // 注意:移动后src中的字符串处于有效但未指定状态
    }
    std::cout << std::endl;
    
    std::cout << "dst: ";
    for (const auto& s : dst) {
        std::cout << "\"" << s << "\" ";
    }
    std::cout << std::endl;
    
    return 0;
}

3.4. 迭代器特性

迭代器特性(iterator_traits)是一种模板结构,用于获取迭代器的相关类型信息。它对于编写通用算法非常重要,因为算法需要知道迭代器所指元素的类型等信息。

迭代器特性定义了以下类型:

value_type:迭代器指向的元素的类型
difference_type:两个迭代器之间距离的类型(通常为ptrdiff_t)
pointer:指向元素的指针类型
reference:元素的引用类型
iterator_category:迭代器的类别(五种之一)

4.函数对象(Function Objects)

  • STL中的函数对象(Function Objects)也称为仿函数(Functors)。它们是行为类似函数的对象,通过重载函数调用运算符(operator())来实现。函数对象可以像函数一样被调用,同时可以拥有状态(即数据成员),因此比普通函数更加灵活。
  • 函数对象的优点:
    1.可以拥有状态:因为函数对象是类实例,可以拥有成员变量,从而记录状态。
    2.可以作为模板参数传递:函数对象的类型可以作为模板参数,从而在编译时进行优化。
    3.可以被内联:函数对象的operator()可以被编译器内联,提高性能。

4.1.STL中预定义的函数对象

STL在<functional>头文件中定义了一些常用的函数对象,分为以下几类:

  • 算术函数对象:
#include <functional>
#include <iostream>

void arithmetic_functors() {
    // plus: 加法
    std::plus<int> add;
    std::cout << "10 + 5 = " << add(10, 5) << std::endl;  // 15
    
    // minus: 减法
    std::minus<int> sub;
    std::cout << "10 - 5 = " << sub(10, 5) << std::endl;  // 5
    
    // multiplies: 乘法
    std::multiplies<int> mul;
    std::cout << "10 * 5 = " << mul(10, 5) << std::endl;  // 50
    
    // divides: 除法
    std::divides<int> div;
    std::cout << "10 / 5 = " << div(10, 5) << std::endl;  // 2
    
    // modulus: 取模
    std::modulus<int> mod;
    std::cout << "10 % 3 = " << mod(10, 3) << std::endl;  // 1
    
    // negate: 取负
    std::negate<int> neg;
    std::cout << "-10 = " << neg(10) << std::endl;  // -10
}
  • 比较函数对象:
void comparison_functors() {
    // equal_to: 等于
    std::equal_to<int> eq;
    std::cout << "10 == 10: " << eq(10, 10) << std::endl;  // true
    std::cout << "10 == 5: " << eq(10, 5) << std::endl;    // false
    
    // not_equal_to: 不等于
    std::not_equal_to<int> neq;
    std::cout << "10 != 5: " << neq(10, 5) << std::endl;   // true
    
    // greater: 大于
    std::greater<int> gt;
    std::cout << "10 > 5: " << gt(10, 5) << std::endl;     // true
    
    // less: 小于
    std::less<int> lt;
    std::cout << "10 < 5: " << lt(10, 5) << std::endl;     // false
    
    // greater_equal: 大于等于
    std::greater_equal<int> ge;
    std::cout << "10 >= 10: " << ge(10, 10) << std::endl;  // true
    
    // less_equal: 小于等于
    std::less_equal<int> le;
    std::cout << "5 <= 10: " << le(5, 10) << std::endl;    // true
    
    // 在算法中使用比较函数对象
    std::vector<int> v = {5, 3, 1, 4, 2};
    
    // 降序排序
    std::sort(v.begin(), v.end(), std::greater<int>());
    std::cout << "降序排序: ";
    for (int x : v) std::cout << x << " ";  // 5 4 3 2 1
    std::cout << std::endl;
    
    // 升序排序(默认)
    std::sort(v.begin(), v.end(), std::less<int>());
    std::cout << "升序排序: ";
    for (int x : v) std::cout << x << " ";  // 1 2 3 4 5
    std::cout << std::endl;
}
  • 逻辑函数对象:
void logical_functors() {
    // logical_and: 逻辑与
    std::logical_and<bool> land;
    std::cout << "true && false: " << land(true, false) << std::endl;  // false
    std::cout << "true && true: " << land(true, true) << std::endl;    // true
    
    // logical_or: 逻辑或
    std::logical_or<bool> lor;
    std::cout << "true || false: " << lor(true, false) << std::endl;  // true
    std::cout << "false || false: " << lor(false, false) << std::endl; // false
    
    // logical_not: 逻辑非
    std::logical_not<bool> lnot;
    std::cout << "!true: " << lnot(true) << std::endl;   // false
    std::cout << "!false: " << lnot(false) << std::endl; // true
    
    // 在算法中使用逻辑函数对象
    std::vector<bool> flags = {true, false, true, false, true};
    
    // 检查是否所有元素都为true
    bool all_true = std::all_of(flags.begin(), flags.end(), 
                                [](bool b) { return b; });
    std::cout << "所有元素都为true: " << all_true << std::endl;  // false
    
    // 检查是否有任意元素为true
    bool any_true = std::any_of(flags.begin(), flags.end(), 
                                [](bool b) { return b; });
    std::cout << "有任意元素为true: " << any_true << std::endl;  // true
}
  • 位运算函数对象(C++11引入):
void bitwise_functors() {
    // bit_and: 位与
    std::bit_and<int> band;
    int result = band(0b1010, 0b1100);  // 0b1000 -> 8
    std::cout << "0b1010 & 0b1100 = " << result << std::endl;  // 8
    
    // bit_or: 位或
    std::bit_or<int> bor;
    result = bor(0b1010, 0b1100);       // 0b1110 -> 14
    std::cout << "0b1010 | 0b1100 = " << result << std::endl;  // 14
    
    // bit_xor: 位异或
    std::bit_xor<int> bxor;
    result = bxor(0b1010, 0b1100);      // 0b0110 -> 6
    std::cout << "0b1010 ^ 0b1100 = " << result << std::endl;  // 6
    
    // 在算法中使用位运算函数对象
    std::vector<int> v1 = {1, 2, 3, 4, 5};
    std::vector<int> v2 = {5, 4, 3, 2, 1};
    std::vector<int> result_vec(5);
    
    // 对两个vector进行位与操作
    std::transform(v1.begin(), v1.end(), v2.begin(), result_vec.begin(),
                   std::bit_and<int>());
    
    std::cout << "位与结果: ";
    for (int x : result_vec) std::cout << x << " ";  // 1&5=1, 2&4=0, 3&3=3, 4&2=0, 5&1=1
    std::cout << std::endl;
}

4.2. 自定义函数对象

我们可以通过定义一个类并重载operator()来创建自定义函数对象。

  • 基本函数对象:
class BasicFunctor {
public:
    // 无状态函数对象
    int operator()(int a, int b) const {
        return a + b;
    }
};

void basic_custom_functor() {
    BasicFunctor adder;
    std::cout << "5 + 3 = " << adder(5, 3) << std::endl;
    
    // 临时对象调用
    std::cout << "10 + 20 = " << BasicFunctor()(10, 20) << std::endl;
}
  • 有状态函数对象:
class StatefulFunctor {
private:
    int count;
    int increment;
public:
    StatefulFunctor(int inc = 1) : count(0), increment(inc) {}
    
    int operator()() {
        count += increment;
        return count;
    }
    
    int getCount() const { return count; }
    void reset() { count = 0; }
};

void stateful_functor_example() {
    StatefulFunctor counter1;           // 默认每次增加1
    StatefulFunctor counter2(5);        // 每次增加5
    
    std::cout << "counter1: ";
    for (int i = 0; i < 5; ++i) {
        std::cout << counter1() << " ";  // 1 2 3 4 5
    }
    std::cout << std::endl;
    
    std::cout << "counter2: ";
    for (int i = 0; i < 5; ++i) {
        std::cout << counter2() << " ";  // 5 10 15 20 25
    }
    std::cout << std::endl;
    
    // 在算法中使用有状态函数对象
    std::vector<int> numbers(10);
    StatefulFunctor generator(2);
    
    std::generate(numbers.begin(), numbers.end(), generator);
    
    std::cout << "生成的序列: ";
    for (int n : numbers) {
        std::cout << n << " ";  // 2 4 6 8 10 12 14 16 18 20
    }
    std::cout << std::endl;
}

4.3. 函数适配器

函数适配器是用来适配函数对象,使其与其他函数对象或值组合,形成新的函数对象。C++11之后,函数适配器的使用减少,因为lambda表达式更灵活。但了解一些传统的适配器仍有必要:

  • bind(C++11引入)- 参数绑定:可以绑定函数对象的参数,并可以重新排列参数顺序
#include <functional>
#include <iostream>

void bind_examples() {
    using namespace std::placeholders;  // 使用占位符 _1, _2, _3...
    
    // 普通函数
    int multiply(int a, int b) {
        return a * b;
    }
    
    // 绑定第一个参数
    auto multiply_by_5 = std::bind(multiply, 5, _1);
    std::cout << "5 * 10 = " << multiply_by_5(10) << std::endl;  // 50
    
    // 绑定第二个参数
    auto multiply_by_3 = std::bind(multiply, _1, 3);
    std::cout << "10 * 3 = " << multiply_by_3(10) << std::endl;  // 30
    
    // 交换参数顺序
    auto multiply_reverse = std::bind(multiply, _2, _1);
    std::cout << "交换参数: " << multiply_reverse(5, 10) << std::endl;  // 50
    
    // 绑定成员函数
    class Calculator {
    public:
        int add(int a, int b) const {
            return a + b;
        }
    };
    
    Calculator calc;
    auto add_10 = std::bind(&Calculator::add, &calc, _1, 10);
    std::cout << "add(5, 10) = " << add_10(5) << std::endl;  // 15
    
    // 绑定数据成员
    struct Point {
        int x, y;
    };
    
    Point p = {10, 20};
    auto get_x = std::bind(&Point::x, _1);
    std::cout << "p.x = " << get_x(p) << std::endl;  // 10
    
    // 组合绑定
    auto complex = std::bind(multiply, 
                            std::bind(std::plus<int>(), _1, 5),  // (x + 5)
                            _2);                                 // * y
    std::cout << "(5 + 5) * 2 = " << complex(5, 2) << std::endl;  // 20
}
  • function(C++11引入)- 函数包装器
#include <functional>
#include <iostream>

void function_examples() {
    // 包装普通函数
    int add(int a, int b) { return a + b; }
    
    std::function<int(int, int)> func1 = add;
    std::cout << "add(10, 20) = " << func1(10, 20) << std::endl;  // 30
    
    // 包装函数对象
    struct Multiply {
        int operator()(int a, int b) const {
            return a * b;
        }
    };
    
    Multiply mult;
    std::function<int(int, int)> func2 = mult;
    std::cout << "mult(10, 20) = " << func2(10, 20) << std::endl;  // 200
    
    // 包装lambda表达式
    std::function<int(int, int)> func3 = [](int a, int b) {
        return a - b;
    };
    std::cout << "subtract(20, 10) = " << func3(20, 10) << std::endl;  // 10
    
    // 包装成员函数
    class Math {
    public:
        int square(int x) const {
            return x * x;
        }
        static int cube(int x) {
            return x * x * x;
        }
    };
    
    Math math;
    std::function<int(const Math&, int)> func4 = &Math::square;
    std::cout << "math.square(5) = " << func4(math, 5) << std::endl;  // 25
    
    std::function<int(int)> func5 = Math::cube;
    std::cout << "Math::cube(3) = " << func5(3) << std::endl;  // 27
    
    // 作为回调函数
    class Button {
        std::function<void()> onClick;
    public:
        void setOnClick(std::function<void()> callback) {
            onClick = callback;
        }
        void click() {
            if (onClick) onClick();
        }
    };
    
    Button button;
    button.setOnClick([]() {
        std::cout << "按钮被点击了!" << std::endl;
    });
    button.click();
    
    // 判断是否为空
    std::function<void()> empty_func;
    if (!empty_func) {
        std::cout << "函数对象为空" << std::endl;
    }
}
  • mem_fn(C++11引入)- 成员函数适配器
#include <functional>
#include <vector>
#include <algorithm>

void mem_fn_examples() {
    class Person {
    public:
        std::string name;
        int age;
        
        Person(std::string n, int a) : name(std::move(n)), age(a) {}
        
        bool isAdult() const {
            return age >= 18;
        }
        
        void birthday() {
            ++age;
        }
        
        std::string getName() const {
            return name;
        }
    };
    
    std::vector<Person> people = {
        {"Alice", 25},
        {"Bob", 17},
        {"Charlie", 30},
        {"David", 16},
        {"Eve", 20}
    };
    
    // 使用mem_fn调用成员函数
    // 统计成年人数量
    int adult_count = std::count_if(people.begin(), people.end(),
                                    std::mem_fn(&Person::isAdult));
    std::cout << "成年人数量: " << adult_count << std::endl;  // 3
    
    // 获取所有人的名字
    std::vector<std::string> names;
    std::transform(people.begin(), people.end(), std::back_inserter(names),
                   std::mem_fn(&Person::getName));
    
    std::cout << "名字: ";
    for (const auto& name : names) {
        std::cout << name << " ";
    }
    std::cout << std::endl;
    
    // 给所有人过生日
    std::for_each(people.begin(), people.end(),
                  std::mem_fn(&Person::birthday));
    
    std::cout << "过生日后的年龄: ";
    for (const auto& p : people) {
        std::cout << p.name << ":" << p.age << " ";
    }
    std::cout << std::endl;
    
    // 访问数据成员
    std::vector<int> ages;
    std::transform(people.begin(), people.end(), std::back_inserter(ages),
                   std::mem_fn(&Person::age));
    
    std::cout << "年龄: ";
    for (int age : ages) {
        std::cout << age << " ";
    }
    std::cout << std::endl;
}
  • 函数对象与lambda表达式:从C++11开始,lambda表达式提供了另一种创建函数对象的方式,通常更简洁。
#include <iostream>
#include <vector>
#include <algorithm>

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

    // 使用lambda表达式作为函数对象
    std::sort(v.begin(), v.end(), [](int a, int b) {
        return a > b; // 降序排序
    });

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

    // lambda表达式可以捕获变量,类似于有状态的函数对象
    int factor = 3;
    std::transform(v.begin(), v.end(), v.begin(), [factor](int x) {
        return x * factor;
    });

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

    return 0;
}

5.适配器(Adapters)

  • STL适配器是一种设计模式,它用于修改或调整其他组件的接口,使其适应不同的需求。STL中的适配器主要分为三类:容器适配器、迭代器适配器和函数适配器。
  1. 适配器分类:
    容器适配器:基于其他容器实现的特殊数据结构
    迭代器适配器:改变迭代器的行为
    函数适配器:修改函数对象的行为
  2. 适配器特点:
    不提供新功能,而是改变现有组件的接口
    实现组件复用
    提高代码的灵活性和可重用性

6.分配器(Allocators)

  • STL中的分配器(Allocators)是用于内存管理的组件,它封装了内存分配和释放的细节,使得STL容器能够独立于具体的内存管理方式。分配器是一个模板类,它定义了如何为容器分配和释放内存,以及如何构造和销毁对象。
  • 分配器的作用
    1.分离内存分配与对象构造
    2.分离对象析构与内存释放
    3.提供一种可定制内存管理策略的机制

6.1.标准分配器

C++标准库提供了一个默认的分配器std::allocator,它使用::operator new和::operator delete来分配和释放内存。

  • 标准分配器(std::allocator)的基本使用
#include <memory>  // allocator 头文件
#include <iostream>

void basic_allocator_usage() {
    // 创建int类型的分配器
    std::allocator<int> alloc;
    
    // 分配可以存储5个int的内存(不构造对象)
    int* p = alloc.allocate(5);
    
    // 在已分配的内存上构造对象
    for (int i = 0; i < 5; ++i) {
        alloc.construct(p + i, i * 10);  // 在p[i]处构造int,值为i*10
    }
    
    // 使用构造的对象
    for (int i = 0; i < 5; ++i) {
        std::cout << p[i] << " ";  // 输出: 0 10 20 30 40
    }
    std::cout << std::endl;
    
    // 销毁对象(但不释放内存)
    for (int i = 0; i < 5; ++i) {
        alloc.destroy(p + i);
    }
    
    // 释放内存
    alloc.deallocate(p, 5);
}
  • 分配器的方法
void allocator_methods() {
    std::allocator<std::string> alloc;
    
    // 1. allocate: 分配原始内存
    std::string* ptr = alloc.allocate(3);  // 分配3个string的内存
    
    // 2. construct: 构造对象(C++17前,C++17后已弃用)
    alloc.construct(ptr, "Hello");         // 构造第一个string
    alloc.construct(ptr + 1, "World");     // 构造第二个string
    alloc.construct(ptr + 2, "!");         // 构造第三个string
    
    // 3. destroy: 销毁对象(C++17前,C++17后已弃用)
    alloc.destroy(ptr);
    alloc.destroy(ptr + 1);
    alloc.destroy(ptr + 2);
    
    // 4. deallocate: 释放内存
    alloc.deallocate(ptr, 3);
    
    // 5. max_size: 最大可分配数量(已弃用)
    // std::size_t max = alloc.max_size();
    
    // C++17推荐使用allocator_traits
}
  • 使用allocator_traits(C++11)
#include <memory>

void allocator_traits_example() {
    using Alloc = std::allocator<int>;
    using Traits = std::allocator_traits<Alloc>;
    
    Alloc alloc;
    
    // 通过traits分配内存
    int* p = Traits::allocate(alloc, 5);
    
    // 通过traits构造对象
    for (int i = 0; i < 5; ++i) {
        Traits::construct(alloc, p + i, i * 10);
    }
    
    for (int i = 0; i < 5; ++i) {
        std::cout << p[i] << " ";  // 0 10 20 30 40
    }
    std::cout << std::endl;
    
    // 通过traits销毁对象
    for (int i = 0; i < 5; ++i) {
        Traits::destroy(alloc, p + i);
    }
    
    // 通过traits释放内存
    Traits::deallocate(alloc, p, 5);
    
    // 获取最大可分配大小
    auto max_size = Traits::max_size(alloc);
    std::cout << "max_size: " << max_size << std::endl;
}

6.2.分配器特性(Allocator Traits)

C++11引入了 allocator_traits,提供了一种统一的方式来访问分配器的属性,即使分配器没有提供某些成员,allocator_traits 也会提供默认实现。

  • allocator_traits 的主要功能
#include <memory>
#include <iostream>

void allocator_traits_features() {
    using Alloc = std::allocator<int>;
    using Traits = std::allocator_traits<Alloc>;
    
    Alloc alloc;
    
    // 1. 类型定义
    using value_type = Traits::value_type;           // int
    using pointer = Traits::pointer;                 // int*
    using const_pointer = Traits::const_pointer;     // const int*
    using void_pointer = Traits::void_pointer;       // void*
    using const_void_pointer = Traits::const_void_pointer;  // const void*
    using difference_type = Traits::difference_type; // ptrdiff_t
    using size_type = Traits::size_type;             // size_t
    
    // 2. 传播特性(用于控制分配器的复制行为)
    using propagate_on_container_copy_assignment = 
        Traits::propagate_on_container_copy_assignment;  // false_type
    using propagate_on_container_move_assignment = 
        Traits::propagate_on_container_move_assignment;  // false_type
    using propagate_on_container_swap = 
        Traits::propagate_on_container_swap;              // false_type
    
    // 3. 分配器是否总是相等
    using is_always_equal = Traits::is_always_equal;      // true_type
    
    std::cout << "propagate_on_container_copy_assignment: " 
              << propagate_on_container_copy_assignment::value << std::endl;
    std::cout << "propagate_on_container_move_assignment: " 
              << propagate_on_container_move_assignment::value << std::endl;
    std::cout << "is_always_equal: " 
              << is_always_equal::value << std::endl;
}

6.3.分配器与容器

  • 容器如何与分配器交互
void container_allocator_interaction() {
    // 1. 容器构造时接收分配器
    std::allocator<int> alloc;
    std::vector<int, std::allocator<int>> v1(alloc);
    
    // 2. 获取容器的分配器
    auto alloc_copy = v1.get_allocator();
    
    // 3. 分配器感知的容器操作
    std::vector<int> v2 = {1, 2, 3, 4, 5};
    std::vector<int> v3(v2.get_allocator());  // 使用相同的分配器
    
    // 4. 使用分配器分配内存
    auto& alloc_ref = v3.get_allocator();
    int* p = alloc_ref.allocate(10);
    
    // ... 使用内存 ...
    
    alloc_ref.deallocate(p, 10);
    
    // 5. 使用自定义分配器的容器
    SimpleAllocator<double> custom_alloc;
    std::vector<double, SimpleAllocator<double>> v4(custom_alloc);
    
    for (int i = 0; i < 10; ++i) {
        v4.push_back(i * 3.14);
    }
}
  • 分配器对容器行为的影响
template<typename T>
class DebugAllocator {
public:
    using value_type = T;
    
    T* allocate(std::size_t n) {
        std::cout << "分配 " << n << " 个 " << typeid(T).name() << std::endl;
        return static_cast<T*>(::operator new(n * sizeof(T)));
    }
    
    void deallocate(T* p, std::size_t n) {
        std::cout << "释放 " << n << " 个 " << typeid(T).name() << std::endl;
        ::operator delete(p);
    }
    
    template<typename U>
    struct rebind {
        using other = DebugAllocator<U>;
    };
};

template<typename T, typename U>
bool operator==(const DebugAllocator<T>&, const DebugAllocator<U>&) {
    return true;
}

template<typename T, typename U>
bool operator!=(const DebugAllocator<T>&, const DebugAllocator<U>&) {
    return false;
}

void allocator_effect_on_container() {
    // 使用调试分配器的vector
    std::cout << "=== vector with debug allocator ===" << std::endl;
    std::vector<int, DebugAllocator<int>> v;
    
    // 观察vector如何分配内存
    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
        std::cout << "size: " << v.size() 
                  << ", capacity: " << v.capacity() << std::endl;
    }
    
    // 使用调试分配器的map
    std::cout << "\n=== map with debug allocator ===" << std::endl;
    std::map<std::string, int, std::less<std::string>, 
             DebugAllocator<std::pair<const std::string, int>>> m;
    
    m["apple"] = 3;
    m["banana"] = 5;
    m["cherry"] = 2;
    m["date"] = 7;
}

6.4.自定义分配器

  • 简单自定义分配器实现
#include <cstdlib>  // malloc, free
#include <iostream>
#include <memory>
#include <new>

template<typename T>
class SimpleAllocator {
public:
    // 类型定义(必须)
    using value_type = T;
    using pointer = T*;
    using const_pointer = const T*;
    using reference = T&;
    using const_reference = const T&;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    
    // 支持分配其他类型的rebind模板(必须)
    template<typename U>
    struct rebind {
        using other = SimpleAllocator<U>;
    };
    
    // 构造函数
    SimpleAllocator() noexcept = default;
    
    template<typename U>
    SimpleAllocator(const SimpleAllocator<U>&) noexcept {}
    
    // 分配内存
    pointer allocate(size_type n, const void* hint = 0) {
        if (n > max_size()) {
            throw std::bad_alloc();
        }
        
        // 使用malloc分配内存
        if (auto p = static_cast<pointer>(std::malloc(n * sizeof(T)))) {
            std::cout << "分配 " << n << " 个 " << typeid(T).name() 
                      << " (" << n * sizeof(T) << " 字节)" << std::endl;
            return p;
        }
        throw std::bad_alloc();
    }
    
    // 释放内存
    void deallocate(pointer p, size_type n) noexcept {
        std::cout << "释放 " << n << " 个 " << typeid(T).name() 
                  << " (" << n * sizeof(T) << " 字节)" << std::endl;
        std::free(p);
    }
    
    // 最大可分配数量
    size_type max_size() const noexcept {
        return std::size_t(-1) / sizeof(T);
    }
    
    // 构造对象
    template<typename U, typename... Args>
    void construct(U* p, Args&&... args) {
        ::new(static_cast<void*>(p)) U(std::forward<Args>(args)...);
    }
    
    // 销毁对象
    template<typename U>
    void destroy(U* p) {
        p->~U();
    }
    
    // 获取地址
    pointer address(reference x) const noexcept { return &x; }
    const_pointer address(const_reference x) const noexcept { return &x; }
};

// 比较操作符(必须)
template<typename T, typename U>
bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&) noexcept {
    return true;
}

template<typename T, typename U>
bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&) noexcept {
    return false;
}

void custom_allocator_example() {
    // 使用自定义分配器的vector
    std::vector<int, SimpleAllocator<int>> v;
    
    for (int i = 0; i < 5; ++i) {
        v.push_back(i * 10);
    }
    
    std::cout << "vector元素: ";
    for (int x : v) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    // 使用自定义分配器的map
    std::map<std::string, int, std::less<std::string>, 
             SimpleAllocator<std::pair<const std::string, int>>> m;
    
    m["apple"] = 3;
    m["banana"] = 5;
    m["cherry"] = 2;
    
    for (const auto& p : m) {
        std::cout << p.first << ": " << p.second << std::endl;
    }
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐