- C++ 基础
- C++ 首页
- C++ 概述
- C++ 环境搭建
- C++ 基本语法
- C++ 注释
- C++ Hello World
- C++ 省略命名空间
- C++ 常量/字面量
- C++ 关键字
- C++ 标识符
- C++ 数据类型
- C++ 数值数据类型
- C++ 字符数据类型
- C++ 布尔数据类型
- C++ 变量类型
- C++ 变量作用域
- C++ 多个变量
- C++ 基本输入/输出
- C++ 修饰符类型
- C++ 存储类
- C++ 运算符
- C++ 数字
- C++ 枚举
- C++ 引用
- C++ 日期和时间
- C++ 控制语句
- C++ 决策
- C++ if 语句
- C++ if else 语句
- C++ 嵌套 if 语句
- C++ switch 语句
- C++ 嵌套 switch 语句
- C++ 循环类型
- C++ while 循环
- C++ for 循环
- C++ do while 循环
- C++ foreach 循环
- C++ 嵌套循环
- C++ break 语句
- C++ continue 语句
- C++ goto 语句
- C++ 构造函数
- C++ 构造函数和析构函数
- C++ 复制构造函数
C++ STL 教程
希望您已经理解了我们之前讨论过的 C++ 模板的概念。C++ STL(标准模板库)是一套强大的 C++ 模板类,它使用模板提供通用类和函数,实现了许多流行且常用的算法和数据结构,例如向量、列表、队列和栈。
C++ 标准模板库的核心是以下三个结构良好的组件:
序号 | 组件及描述 |
---|---|
1 | 容器 容器用于管理特定类型的对象的集合。有几种不同类型的容器,例如 deque、list、vector、map 等。 |
2 | 算法 算法作用于容器。它们提供了执行容器内容初始化、排序、搜索和转换的方法。 |
3 | 迭代器 迭代器用于遍历对象集合的元素。这些集合可能是容器或容器的子集。 |
我们将在下一章讨论 C++ 标准库时讨论所有三个 C++ STL 组件。现在,请记住所有三个组件都有一套丰富的预定义函数,这些函数可以帮助我们以非常简单的方式完成复杂的任务。
示例
让我们来看以下程序,它演示了 vector 容器(一个 C++ 标准模板),它类似于数组,区别在于它在增长时会自动处理自己的存储需求:
#include <iostream> #include <vector> using namespace std; int main() { // create a vector to store int vector<int> vec; int i; // display the original size of vec cout << "vector size = " << vec.size() << endl; // push 5 values into the vector for(i = 0; i < 5; i++) { vec.push_back(i); } // display extended size of vec cout << "extended vector size = " << vec.size() << endl; // access 5 values from the vector for(i = 0; i < 5; i++) { cout << "value of vec [" << i << "] = " << vec[i] << endl; } // use iterator to access the values vector<int>::iterator v = vec.begin(); while( v != vec.end()) { cout << "value of v = " << *v << endl; v++; } return 0; }
当以上代码编译并执行时,会产生以下结果:
vector size = 0 extended vector size = 5 value of vec [0] = 0 value of vec [1] = 1 value of vec [2] = 2 value of vec [3] = 3 value of vec [4] = 4 value of v = 0 value of v = 1 value of v = 2 value of v = 3 value of v = 4
以下是一些关于我们在上述示例中使用的各种函数需要注意的事项:
- push_back() 成员函数在向量的末尾插入值,根据需要扩展其大小。
- size() 函数显示向量的尺寸。
- begin() 函数返回指向向量开头的迭代器。
- end() 函数返回指向向量末尾的迭代器。
C++ 标准模板库组件
C++ 标准模板库的核心是以下四个结构良好的组件:
- 容器
- 算法
- 迭代器
- 仿函数(函数对象)
容器
容器是用于存储和管理数据或对象集合(例如向量、列表、集合和映射)的数据结构。在这里,我们将看到几种类型的容器。
1. 顺序容器
它们是按特定线性顺序存储元素的容器。它们允许直接访问元素以及管理元素顺序和排列的功能。
- 数组 − 这些是固定大小的元素集合。
- 向量 − 它是一个动态数组,可以根据需要调整其大小。
- 双端队列 − 双端队列,允许在两端快速插入和删除。
- 列表 − 一个双向链表,允许双向迭代。
- 前向列表 − 它是一个单向链表,允许高效插入和删除,但只能单向遍历。
- 字符串 − 在 C++ 中,字符串也被认为是顺序容器,它被实现为字符的动态数组,其行为类似于其他顺序容器。
2. 关联容器
它以排序的顺序存储元素,允许根据键快速检索。这些容器以键值对结构工作,其中每个元素都与一个唯一的键关联。此键用于快速访问相应的键值。
3. 无序关联容器
它以无序的方式存储元素,允许根据键高效访问、插入和删除。它们不维护元素的排序顺序,而是使用哈希来组织数据。
- 无序集合 − 它是一组唯一的元素,没有任何特定顺序。
- 无序映射 − 它是一组键值对,没有任何特定顺序。
- 无序多重集 − 它允许重复元素,没有任何特定顺序。
- 无序多重映射 − 它允许重复键,没有任何特定顺序。
4. 容器适配器
它为现有容器提供不同的接口。
算法
C++ 标准模板库 (STL) 中的算法是一个大型函数集合,专门设计用于对容器执行操作。其中,这些算法使用迭代器来遍历容器,而无需了解其内部结构。
非修改顺序算法
- for_each − 它应用于查找范围内的每个元素的函数。
- count − 它计算范围内某个值的出现次数。
- find() − 它查找范围内某个值的第一次出现。
- find_if − 它查找满足谓词的第一个元素。
- find_if_not − 它查找不满足谓词的第一个元素。
- equal − 它检查两个范围是否相等。
- search − 它在一个序列中搜索子序列。
1. 修改顺序算法
- copy() − 它将元素从一个范围复制到另一个范围。
- copy_if − 它将满足谓词的元素复制到另一个范围。
- copy_n − 它将特定数量的元素从一个范围复制到另一个范围。
- move − 它将元素从一个范围移动到另一个范围。
- transform() − 它将函数应用于范围并存储结果。
- remove − 它从范围内删除具有特定值的元素。
- remove_if − 它删除满足谓词的元素。
- unique − 它删除连续的重复元素。
- reverse() − 它反转范围内元素的顺序。
- swap() − 它交换元素。
2. 排序算法
- sort − 它对范围内的元素进行排序。
- stable_sort − 它对元素进行排序,同时保持等效元素的相对顺序。
- partial_sort − 它对范围的一部分进行排序。
- nth_element − 它对范围进行分区,以便第 n 个元素位于其最终位置。
3. 搜索算法
- binary_search − 它检查元素是否存在于排序范围内。
- lower_bound − 它搜索可以插入元素以保持顺序的第一个位置。
- upper_bound − 它搜索大于指定值的第一个元素的位置。
- binary_search − 它检查元素是否存在于排序范围内。
- lower_bound − 它查找可以插入元素以保持顺序的第一个位置。
- upper_bound − 它搜索大于指定值的第一个元素的位置。
- equal_range − 它返回相等元素的范围。
4. 堆算法
- make_heap − 从一个区间创建堆。
- push_heap − 向堆中添加一个元素。
- pop_heap − 从堆中删除最大元素。
- sort_heap − 对堆中的元素进行排序。
5. 集合算法
- set_union − 计算两个集合的并集。
- set_intersection − 计算两个集合的交集。
- set_difference − 计算两个集合的差集。
- set_symmetric_difference − 计算两个集合的对称差集。
6. 数值算法
- accumulate − 计算一个区间的和(或其他操作)。
- inner_product − 计算两个区间的内积。
- adjacent_difference − 计算相邻元素之间的差。
- Partial_sum − 计算一个区间的部分和。
7. 其他算法
- generate − 使用函数生成的值填充一个区间。
- shuffle − 随机打乱一个区间内的元素。
- partition − 根据谓词将元素划分为两组。
迭代器
C++ 标准模板库 (STL) 中的迭代器是充当容器内元素指针的对象,它提供了一个统一的接口来访问和操作数据。它们充当算法和容器之间的桥梁。
函数对象(仿函数)
C++ 中的仿函数(或函数对象)是可以像函数一样调用的对象。它可以像普通函数一样被调用。此功能是通过重载函数调用运算符()来实现的。
在这里,您将根据它们执行的操作探索不同类型的仿函数。
1. 算术仿函数
在 C++ 中,算术运算符用于执行基本的数学运算。以下是常见的算术运算符以及示例。
- 加法 (+) − 将两个值组合起来以产生它们的和。
- 减法 (-) − 计算两个值之间的差。
- 乘法 (*) − 将两个值相乘以产生它们的积。
- 除法 (/) − 将一个值除以另一个值,得到商。
- 模 (%) − 返回一个值除以另一个值的余数。
- 取反 (-) − 返回参数的取反值。
2. 比较仿函数
比较仿函数用于比较值,尤其是在容器中进行排序或搜索时。
- 小于 (<) − 比较并返回第一个值是否小于第二个值。
- 大于 (>) − 比较并返回第一个值是否大于第二个值。
- 小于等于 (≤) − 比较并返回第一个值是否小于等于第二个值。
- 大于等于 (≥) − 比较并返回第一个值是否大于等于第二个值。
- 等于 (=) − 比较并返回两个值是否相等。
- 不等于 (≠) − 比较并返回两个值是否不相等。
3. 逻辑仿函数
逻辑仿函数执行逻辑运算,在涉及布尔逻辑的场景中可能很有用。
- 逻辑与仿函数 (&&) − 如果两个布尔参数中至少有一个或两个为假,则返回假,否则返回真。
- 逻辑或仿函数 (||) − 如果两个布尔参数中至少有一个或两个为真,则返回真。
- 逻辑非仿函数 (!) − 如果布尔参数为假则返回真,反之亦然,它返回提供布尔值的相反值。
4. 位运算仿函数
- bit_and − 对两个操作数执行按位与运算。
- bit_or − 对两个操作数执行按位或运算。
- Bit_xor − 对两个操作数执行按位异或 (XOR) 运算,并返回相应的输出。
实用工具
实用工具是指一系列通用组件,它们在编程中提供基本功能,并允许对数据和类型进行高效操作。
1. 对和元组
- pair − 它是一个容器,包含两个可能不同类型的值,作为第一个和第二个成员。
- tuple − 一个固定大小的集合,可以存储多种不同类型的多个值,可以通过 std::get 访问每个元素。
2. 智能指针
- unique_ptr − 它是一个智能指针,拥有一个动态分配的对象,当指针超出范围时会自动释放它。
- Shared_ptr − 它是一个智能指针,允许多个指针共享一个动态分配对象的拥有权,通过使用引用计数来管理生命周期。
- Weak_ptr − 它是一个智能指针,提供对由 std::shared_ptr 管理的对象的非拥有引用,这可以防止循环引用。
3. 可选、变体和任何类型 (C++17)
- Optional − 它是一个包装器,表示一个可选的值,指示值是否存在。
- variant − 它是一个类型安全的联合,可以保存多个指定类型之一,提供了一种在不产生歧义的情况下处理多种类型的方法。
- any − 它是一个类型安全的容器,用于存储任何类型的值,允许动态类型擦除和运行时类型检查。
4. 内存管理和数值限制
- allocator − 用于管理动态内存。
- numeric_limits − 提供有关基本数据类型属性的信息。
5. 类型特征
它是一组模板,允许您执行编译时类型检查。
- is_same − 它是一个类型特征,检查两个类型是否相同,如果相同则返回真,否则返回假。
- is_integral − 它是一个类型特征,确定给定类型是否为整型(例如,int、char、long),对于整型返回真,对于其他类型返回假。
- is_floating_point − 它是一个类型特征,检查给定类型是否为浮点类型(例如,float、double、long double),对于浮点类型返回真,对于非浮点类型返回假。
- enable_if − 它是一个实用工具,根据编译时条件启用或禁用模板实例化,通常用于 SFINAE(替换失败不是错误)。
基本 STL 功能:简单示例
这是一个演示一些基本 STL 功能的简单示例
#include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> vec = {5, 2, 8, 1, 3}; // Sorting the vector std::sort(vec.begin(), vec.end()); // Displaying sorted elements std::cout << "Sorted vector: "; for (int num : vec) { std::cout << num << " "; } std::cout << std::endl; // Finding an element auto it = std::find(vec.begin(), vec.end(), 3); if (it != vec.end()) { std::cout << "Element 3 found at position: " << std::distance(vec.begin(), it) << std::endl; } else { std::cout << "Element 3 not found" << std::endl; } return 0; }
输出
Sorted vector: 1 2 3 5 8 Element 3 found at position: 2
解释
此代码在多个地方提供了 STL 的使用,
- std::vector<int> vec − 上述程序使用了 std::vector,它是一个 STL 容器,允许动态数组管理。
- std::sort(vec.begin(), vec.end()) − 此函数是 STL 算法的一部分,它作用于容器,按升序对向量的元素进行排序。
- std::find(vec.begin(), vec.end(), 3) − 此函数在向量中搜索值 3,如果找到则返回指向它的迭代器。
- begin() 和 vec.end() − 这些函数分别返回指向向量开头和向量末尾之后的迭代器。
- std::distance(vec.begin(), it) − 此函数计算两个迭代器之间的元素数量(在本例中,从向量的开头到找到的迭代器),有效地给出找到的元素的索引。
使用 STL 的好处
在 C++ 中使用标准模板库 (STL) 有很多好处,因为它提供了一个庞大的预定义数据结构和算法集合,从而节省了时间和精力,减少了从头实现这些结构和算法的需要。它还促进了代码重用、模块化、类型安全和灵活性。这使得相同的代码可以与不同的数据类型一起工作。总的来说,它提高了编程效率和代码质量。