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++ 运算符 C++ 算术运算符 C++ 关系运算符 C++ 逻辑运算符 C++ 位运算符 C++ 赋值运算符 C++ sizeof 运算符 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++ 字符串长度 C++ 字符串连接 C++ 字符串比较

C++ 函数

C++ 函数 C++ 多函数参数 C++ 递归函数 C++ 返回值 C++ 函数重载 C++ 函数重写 C++ 默认参数

C++ 数组

C++ 数组 C++ 多维数组 C++ 指向数组的指针 C++ 将数组传递给函数 C++ 从函数返回数组

C++ 结构 &联合

C++ 结构 C++ 联合

C++ 指针

C++ 指针 C++ 解引用 C++ 修改指针

C++ 类和对象

C++ 面向对象 C++ 类 &对象 C++ 类成员函数 C++ 类访问修饰符 C++ 静态类成员 C++ 静态数据成员 C++ 静态成员函数 C++ 内联函数 C++ this 指针 C++ 友元函数 C++ 指向类的指针

C++ 构造函数

C++ 构造函数 &析构函数 C++ 默认构造函数 C++ 参数化构造函数 C++ 复制构造函数 C++ 构造函数重载 C++ 带默认参数的构造函数 C++ 委托构造函数 C++ 构造函数初始化列表 C++ 使用构造函数动态初始化

C++ 继承

C++ 继承 C++ 多重继承 C++ 多级继承

C++ 面向对象

C++ 重载 C++ 多态性 C++ 抽象 C++ 封装 C++ 接口 C++ 虚函数 C++ 纯虚函数与抽象类

C++ 文件处理

C++ 文件和流 C++ 文件读取

C++ 进阶

C++ 异常处理 C++ 动态内存 C++ 命名空间 C++ 模板 C++ 预处理器 C++ 信号处理 C++ 多线程 C++ Web 编程 C++ 套接字编程 C++ 并发 C++ 高级概念 C++ Lambda 表达式 C++ unordered_multiset

C++ 实用资源

C++ 问答 C++ 快速指南 C++ 速查表 C++ STL 教程 C++ 标准库 C++ 实用资源 C++ 讨论


C++ STL 教程

希望您已经理解了我们之前讨论过的 C++ 模板的概念。C++ STL(标准模板库)是一组功能强大的 C++ 模板类,它为通用类和函数提供了模板,这些模板实现了许多流行且常用的算法和数据结构,例如向量、列表、队列和堆栈。

C++ 标准模板库的核心是以下三个结构良好的组件 -

Sr.No 组件和描述
1

容器

容器用于管理特定类型对象的集合。容器有多种类型,例如双端队列 (deque)、列表 (list)、向量 (vector)、映射 (map) 等。

2

算法

算法作用于容器。它们提供对容器内容进行初始化、排序、搜索和转换的方法。

3

迭代器

迭代器用于遍历对象集合的元素。这些集合可以是容器,也可以是容器的子集。

下一章讨论 C++ 标准库 (C++ STL) 时,我们将讨论所有三个 C++ STL 组件。现在,请记住,这三个组件都拥有丰富的预定义函数,可以帮助我们以非常轻松的方式完成复杂的任务。

示例

让我们以以下程序为例,该程序演示了向量容器(C++ 标准模板),它类似于数组,但有一个例外:当数组增长时,它会自动处理自身的存储需求 -

#include <iostream>
#include <vector>
using namespace std;
 
int main() {

   // 创建一个向量来存储 int
   vector<int> vec; 
   int i;

   // 显示 vec 的原始大小
   cout << "vector size = " << vec.size() << endl;

   // 将 5 个值推送到向量中
   for(i = 0; i < 5; i++) {
      vec.push_back(i);
   }

   // 显示 vec 的扩展大小
   cout << "extended vector size = " << vec.size() << endl;

   // 从向量中访问 5 个值
   for(i = 0; i < 5; i++) {
      cout << "value of vec [" << i << "] = " << vec[i] << endl;
   }

   // 使用迭代器访问值
   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. 关联容器

它按排序顺序存储元素,从而允许基于键快速检索。这些容器采用键值对结构,其中每个元素都与一个唯一的键相关联。此键用于快速访问相应的值。

  • Set − 它是按特定顺序排序的唯一元素的集合。
  • Map − 它是键值对的集合,其中键是唯一的。
  • Multiset − 它类似于集合,但允许重复元素。
  • Multimap − 它类似于地图,但允许重复键。

3.无序关联容器

它以无序的方式存储元素,从而允许基于键进行高效的访问、插入和删除。它们不维护元素的排序顺序,而是使用散列来组织数据。

  • unordered_set − 它是唯一元素的集合,没有任何特定顺序。
  • unordered_map − 它是键值对的集合,没有特定顺序。
  • unordered_multiset − 它允许重复元素,而没有特定顺序。
  • unordered_multimap − 它允许重复键。没有特定顺序。

4. 容器适配器

它为现有容器提供了不同的接口。

  • − 它是一种遵循后进先出 (LIFO) 原则的数据结构。
  • 队列 − 它是一种遵循先进先出 (FIFO) 原则的数据结构。
  • 优先级队列 − 它是一种特殊类型的队列,其中元素根据优先级进行移除。

算法

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. 堆算法

  • ma​​ke_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.比较函子

比较函子用于比较值,尤其是在容器中排序或搜索时。

  • 小于 (<) − 如果第一个值小于第二个值,则比较并返回 true。
  • 大于 (>) − 如果第一个值大于第二个值,则比较并返回 true。
  • 小于或等于 (≤) − 如果第一个值小于或等于第二个值,则比较并返回 true。
  • 大于或等于 (≥) − 如果第一个值大于或等于第二个值,则比较并返回 true。
  • 等于 (=) − 如果相等,则比较并返回 true。
  • 不等于(≠) − 比较两个布尔值,如果不相等则返回 true。

3. 逻辑函子

逻辑函子执行逻辑运算,在涉及布尔逻辑的场景中非常有用。

  • 逻辑与函子 (&&) − 如果两个布尔参数中至少有一个或两个为 false,则返回 false;否则返回 true。
  • 逻辑或函子 (||) − 如果两个布尔参数中至少有一个或两个为 true,则返回 true。
  • 逻辑非函子 (!) − 如果布尔参数为 false,则返回 true;反之,返回与提供的布尔值相反的值。

4.按位函数

  • bit_and − 对两个操作数执行按位"与"运算,
  • bit_or − 对两个操作数执行按位"或"运算,
  • Bit_xor − 对两个操作数执行按位"异或"运算,并返回相应的输出。

实用程序

实用程序是指一组通用组件,它们提供编程的基本功能,并允许对数据和类型进行高效的操作。

1. 对和元组

  • − 它是一个容器,可以容纳两个可能不同类型的值,分别作为第一和第二个成员。
  • 元组 − 一个固定大小的集合,可以存储多个不同类型的值,并通过 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 − 它是一个类型特征,用于检查两个类型是否相同,如果相同则返回 true,否则返回 false。
  • is_integral − 它是一个类型特征,用于确定给定类型是否为整数类型(例如,int、char、long),对于整数类型返回 true,对于其他类型返回 false。
  • is_floating_point − 它是一个类型特征,用于检查给定类型是否为浮点类型(例如,float、double、long double),对于浮点类型返回 true,对于非浮点类型返回 false。
  • enable_if − 它是一个实用程序,用于根据编译时条件,通常用于 SFINAE(替换失败不是错误)。

STL 基本功能:简单示例

这是一个演示 STL 基本功能的简单示例

#include <iostream>
#include <vector>
#include <algorithm>

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

   // 对向量进行排序
   std::sort(vec.begin(), vec.end());

   // 显示已排序的元素
   std::cout << "Sorted vector: ";
   for (int num : vec) {
      std::cout << num << " ";
   }
   std::cout << std::endl;

   // 查找元素
   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) 有很多好处,因为它提供了大量预定义的数据结构和算法,从而节省时间和精力,并减少了从头实现这些结构和算法的需求。它还促进了代码重用、模块化、类型安全和灵活性。这使得相同的代码可以处理不同的数据类型。总的来说,它提高了编程效率和代码质量。