【C++提高编程-07】----C++ STL常用算法之遍历算法和算术生成算法

2024-06-16 20:12

本文主要是介绍【C++提高编程-07】----C++ STL常用算法之遍历算法和算术生成算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

34889d2e7fec4a02bb0ae3a22b011a2a.png

🎩 欢迎来到技术探索的奇幻世界👨‍💻

📜 个人主页:@一伦明悦-CSDN博客

✍🏻 作者简介: C++软件开发、Python机器学习爱好者

🗣️ 互动与支持💬评论      👍🏻点赞      📂收藏     👀关注+

如果文章有所帮助,欢迎留下您宝贵的评论,

点赞加收藏支持我,点击关注,一起进步!

前言

       STL(Standard Template Library)是C++标准库的一部分,提供了丰富的数据结构和算法,用于处理数据和实现常见的计算任务。STL中的算法分为几类,包括遍历算法、修改算法、排序算法、查找算法、数值算法等,每类算法都有其特定的应用场景和功能。

正文

01-遍历算法之for_each用法

  for_each 是一种遍历算法,用于对指定范围内的每个元素执行特定操作。它的使用方式相对简单,但需要传入一个函数或函数对象作为操作的执行体。以下是关于 for_each 的详细介绍和用法示例:

for_each 用法详解

语法

template <class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f);
  • InputIterator:表示容器或范围的起始位置的迭代器。
  • Function:表示执行的操作,可以是函数或函数对象(仿函数)。

参数

  • first:表示要处理的范围的起始位置。
  • last:表示要处理的范围的结束位置,不包含在范围内。
  • f:表示要执行的操作,可以是函数或函数对象。

功能

for_each 对 [first, last) 范围内的每个元素执行 f 操作。

返回值

返回值类型为 Function,通常是传入的函数或函数对象 f

示例

假设有一个整数数组 numbers,我们想要将每个元素加倍并输出结果。可以这样使用 for_each

#include <iostream>
#include <vector>
#include <algorithm>void doubleAndPrint(int x) {std::cout << x * 2 << " ";
}int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};// 使用 for_each 执行操作std::for_each(numbers.begin(), numbers.end(), doubleAndPrint);return 0;
}

输出结果将是 2 4 6 8 10,这里 doubleAndPrint 函数就是传入 for_each 的操作函数。在实际使用中,可以根据需要定义不同的操作函数或使用 lambda 表达式作为 for_each 的操作体。

注意事项

  • for_each 并不会改变容器中元素的值,它只是对每个元素执行操作。
  • 传入的操作函数或函数对象应符合对应的参数和返回值要求,以确保正确执行操作。

通过灵活运用 for_each 算法,可以简化遍历操作的代码,提高代码的可读性和维护性。

下面给出具体代码分析应用过程

这段代码展示了如何使用 for_each 算法进行遍历操作,分别使用普通函数和函数对象作为操作体。让我简要解释一下这部分代码:

  1. 头文件包含

    #include <algorithm>
    #include <vector>
    

    这里包含了使用到的标准库头文件 <algorithm> 和 <vector>

  2. 普通函数 print01

    void print01(int val)
    {cout << val << " ";
    }
    

    print01 是一个普通函数,用于打印传入的整数 val

  3. 函数对象 print02

    class print02
    {
    public:void operator()(int val){cout << val << " ";}
    };
    

    print02 是一个函数对象(也称为仿函数),重载了函数调用运算符 operator(),用于打印传入的整数 val

  4. test01 函数

    void test01() {vector<int> v;for (int i = 0; i < 10; i++){v.push_back(i);}// 使用 for_each 算法调用普通函数 print01for_each(v.begin(), v.end(), print01);cout << endl;// 使用 for_each 算法调用函数对象 print02for_each(v.begin(), v.end(), print02());cout << endl;
    }
    
    • 在 test01 函数中,首先创建了一个 vector<int> 容器 v,并将整数 0 到 9 添加到容器中。
    • 然后使用 for_each 算法分别调用了 print01 和 print02 函数对象,对容器 v 中的每个元素执行打印操作。
  5. main 函数

    int main() {test01();system("pause");return 0;
    }
    

    main 函数调用了 test01 函数,展示了 for_each 算法的基本用法和不同操作体的应用。

总结:

  • 这段代码演示了如何使用 for_each 算法对容器进行遍历操作,可以通过普通函数或函数对象来定义具体的操作。
  • 函数对象的使用使得可以在一个地方定义多个不同的操作,增加了代码的灵活性和可复用性。
  • for_each 算法不会修改容器中的元素,只是对每个元素执行指定的操作,这符合算法的设计初衷。

通过这样的方式,可以简化遍历操作的代码实现,并使代码更加清晰和易于维护。

#include <algorithm>
#include <vector>
//普通函数
void print01(int val)
{cout << val << " ";
}
//函数对象
class print02
{
public:void operator()(int val){cout << val << " ";}
};
//for_each算法基本用法
void test01() {vector<int> v;for (int i = 0; i < 10; i++){v.push_back(i);}//遍历算法for_each(v.begin(), v.end(), print01);cout << endl;for_each(v.begin(), v.end(), print02());cout << endl;
}
int main() {test01();system("pause");return 0;
}

02-遍历算法之transform用法

        transform 是另一种常用的STL遍历算法,与 for_each 不同的是,它不仅可以对容器中的每个元素执行操作,还可以将操作的结果存储到另一个容器或同一容器的不同位置。以下是关于 transform 的详细介绍和用法示例:

transform 用法详解

语法

template <class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator transform(InputIterator first1, InputIterator last1,OutputIterator result, UnaryOperation op);
  • InputIterator:表示容器或范围的起始位置的迭代器。
  • OutputIterator:表示结果存储位置的迭代器。
  • UnaryOperation:表示执行的操作,通常是一个函数对象(一元函数)。

参数

  • first1:表示要处理的范围的起始位置。
  • last1:表示要处理的范围的结束位置,不包含在范围内。
  • result:表示操作结果的存储位置,可以是另一个容器的 begin() 迭代器或插入位置迭代器。
  • op:表示要执行的操作,通常是一个函数对象,接受一个参数并返回结果。

功能

transform 对 [first1, last1) 范围内的每个元素应用 op 操作,并将结果存储到 result 指定的位置。

返回值

返回一个指向存储结果的迭代器 result + (last1 - first1)

示例

假设有一个整数数组 numbers,我们想要将每个元素加倍并存储到另一个数组 doubled_numbers 中。可以这样使用 transform

#include <iostream>
#include <vector>
#include <algorithm>// 定义一个函数对象,用于将元素加倍
struct Double {int operator()(int x) const { return x * 2; }
};int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};std::vector<int> doubled_numbers;// 使用 transform 执行操作std::transform(numbers.begin(), numbers.end(), std::back_inserter(doubled_numbers), Double());// 输出结果for (auto num : doubled_numbers) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

        输出结果将是 2 4 6 8 10,这里 Double 是一个函数对象,作为 transform 的操作体。在实际使用中,也可以使用 lambda 表达式或其他函数对象来定义操作体 op

注意事项

  • transform 可以将操作的结果存储到另一个容器(如示例中的 doubled_numbers),这对于在算法中生成新的数据集合非常有用。
  • 操作体 op 必须是一个一元函数,接受一个参数并返回操作后的结果。
  • 如果 result 容器的大小不足以容纳结果,则程序行为未定义;通常情况下应使用 std::back_inserter 等函数来动态扩展容器大小。

        通过 transform 算法,可以将处理数据和存储结果有效地分离,提高了代码的模块化和可维护性,是处理数据转换和映射的常用工具之一。

下面给出代码分析应用过程:

这段代码演示了如何使用 transform 算法来对一个容器中的元素进行转换,并将结果存储到另一个容器中。让我来简要解释一下:

  1. 头文件包含

    #include <vector>
    #include <algorithm>
    

    这里包含了使用到的标准库头文件 <vector> 和 <algorithm>

  2. 函数对象 TransForm

    class TransForm
    {
    public:int operator()(int val){return val;}
    };
    

    TransForm 是一个函数对象(仿函数),重载了函数调用运算符 operator(),用于对传入的整数 val 进行转换操作。在这个例子中,它实际上是一个恒等函数,返回原始的输入值。

  3. 函数对象 MyPrint

    class MyPrint
    {
    public:void operator()(int val){cout << val << " ";}
    };
    

    MyPrint 是另一个函数对象,用于打印传入的整数 val

  4. test01 函数

    void test01()
    {vector<int> v;for (int i = 0; i < 10; i++){v.push_back(i);}vector<int> vTarget; // 目标容器vTarget.resize(v.size()); // 目标容器需要提前开辟空间// 使用 transform 算法对容器 v 中的每个元素应用 TransForm,并将结果存储到 vTarget 中transform(v.begin(), v.end(), vTarget.begin(), TransForm());// 使用 for_each 算法打印 vTarget 中的每个元素for_each(vTarget.begin(), vTarget.end(), MyPrint());
    }
    
    • 在 test01 函数中,首先创建了一个 vector<int> 容器 v,并向其中插入整数 0 到 9。
    • 创建了另一个 vector<int> 容器 vTarget 作为目标容器,并调整其大小以匹配 v 的大小。
    • 使用 transform 算法对容器 v 中的每个元素应用 TransForm 函数对象,并将结果存储到 vTarget 中。
    • 最后,使用 for_each 算法和 MyPrint 函数对象打印 vTarget 中的每个元素。
  5. main 函数

    int main() {test01();system("pause");return 0;
    }
    

    main 函数调用了 test01 函数,展示了 transform 算法的基本用法和将操作结果存储到另一个容器的实际应用。

总结:

  • transform 算法能够对一个容器中的元素进行操作,并将结果存储到另一个容器或同一容器的不同位置,比如示例中的 vTarget
  • 使用函数对象(如 TransForm 和 MyPrint)可以灵活定义操作,增强代码的可复用性和可维护性。
  • 需要注意的是,目标容器在使用 transform 算法之前需要预先分配足够的空间,以确保存储结果的正确性。

通过这样的方式,可以有效地进行数据转换和处理,使代码更加清晰和模块化。

#include<vector>
#include<algorithm>
//常用遍历算法 搬运 transform
class TransForm
{
public:int operator()(int val){return val;}
};
class MyPrint
{
public:void operator()(int val){cout << val << " ";}
};
void test01()
{vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}vector<int>vTarget; //目标容器vTarget.resize(v.size()); // 目标容器需要提前开辟空间transform(v.begin(), v.end(), vTarget.begin(), TransForm());for_each(vTarget.begin(), vTarget.end(), MyPrint());
}
int main() {test01();system("pause");return 0;
}

03-算术生成算法之accumulate用法

        accumulate 是另一个常用的STL算法,用于计算序列中元素的累加值。以下是关于 accumulate 的详细介绍和用法示例:

accumulate 用法详解

语法

template <class InputIterator, class T>
T accumulate(InputIterator first, InputIterator last, T init);
  • InputIterator:表示容器或范围的起始位置的迭代器。
  • T:表示累加结果的类型,通常是元素类型的累加结果类型。
  • init:表示初始值,累加的起始点。

参数

  • first:表示要累加的范围的起始位置。
  • last:表示要累加的范围的结束位置,不包含在范围内。
  • init:表示累加的初始值,累加从这个值开始。

功能

accumulate 对 [first, last) 范围内的元素进行累加,初始值为 init,并返回累加的结果。

返回值

返回累加后的结果,类型为 T

示例

假设有一个整数数组 numbers,我们想要计算数组中所有元素的累加和。可以这样使用 accumulate

#include <iostream>
#include <vector>
#include <numeric> // 包含 accumulate 函数int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};// 使用 accumulate 计算累加和int sum = std::accumulate(numbers.begin(), numbers.end(), 0);std::cout << "Sum of elements: " << sum << std::endl;return 0;
}

输出结果将是 Sum of elements: 15。在这个例子中,accumulate 函数将整数数组 numbers 中的所有元素累加起来,初始值为 0

注意事项

  • accumulate 可以用于各种数据类型,不限于整数。
  • 初始值 init 的类型必须与累加结果的类型相容,通常为整数或浮点数。
  • 如果范围 [first, last) 是空的,accumulate 将直接返回初始值 init

        通过 accumulate 算法,可以方便地计算序列中元素的累加和,是处理累加操作的常用工具之一。

 下面给出具体代码分析应用过程:

这段代码展示了如何使用 accumulate 算法来计算整数向量中所有元素的累加和。让我来简要解释一下:

  1. 头文件包含

    #include <numeric>
    #include <vector>
    

    这里包含了使用到的标准库头文件 <numeric> 和 <vector>

  2. test01 函数

    void test01()
    {vector<int> v;for (int i = 0; i <= 100; i++) {v.push_back(i);}int total = accumulate(v.begin(), v.end(), 0);cout << "total = " << total << endl;
    }
    
    • 在 test01 函数中,首先创建了一个 vector<int> 容器 v,并使用循环将整数 0 到 100 插入到向量中。
    • 调用 accumulate 算法计算了容器 v 中所有元素的累加和。参数解释如下:
      • v.begin() 和 v.end() 表示累加的范围是从容器 v 的开头到末尾(不包括末尾)。
      • 0 是累加的初始值,即从0开始累加。
    • 将计算得到的总和 total 输出到标准输出流 cout 中。
  3. main 函数

    int main() {test01();system("pause");return 0;
    }
    

    main 函数调用了 test01 函数,展示了 accumulate 算法的使用方式和计算结果的输出。

总结:

  • accumulate 算法能够方便地对容器中的元素进行累加操作,从而计算它们的总和。
  • 初始值 0 确保了即使容器为空,也能正确返回初始值作为累加结果。
  • 使用 accumulate 算法可以避免显式使用循环来计算累加和,简化了代码并提高了可读性。

通过这样的方式,可以快速、有效地处理需要累加操作的情况,适用于各种数据类型和复杂度的累加需求。

#include <numeric>
#include <vector>
void test01()
{vector<int> v;for (int i = 0; i <= 100; i++) {v.push_back(i);}int total = accumulate(v.begin(), v.end(), 0);cout << "total = " << total << endl;
}
int main() {test01();system("pause");return 0;
}

04-算术生成算法之fill用法

       fill 是STL中的一个算法,用于将指定范围内的所有元素设置为给定的值。以下是关于 fill 的详细介绍和用法示例:

fill 用法详解

语法

template <class ForwardIterator, class T>
void fill (ForwardIterator first, ForwardIterator last, const T& value);
  • ForwardIterator:表示容器或范围的起始位置的迭代器类型。
  • T:表示要填充的值的类型。
  • first:表示要填充的范围的起始位置。
  • last:表示要填充的范围的结束位置,不包含在范围内。
  • value:表示要填充到范围中的值。

参数

  • first:要填充的范围的起始位置。
  • last:要填充的范围的结束位置,不包含在范围内。
  • value:要填充到范围中的值。

功能

fill 算法用指定的值 value 填充 [first, last) 范围内的所有元素。

返回值

无。

示例

假设有一个整数数组 numbers,我们想要将数组中的所有元素设置为 0。可以这样使用 fill

#include <iostream>
#include <vector>
#include <algorithm> // 包含 fill 函数int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};// 使用 fill 将数组中所有元素设置为 0std::fill(numbers.begin(), numbers.end(), 0);// 打印填充后的结果for (int num : numbers) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

输出结果将是 0 0 0 0 0。在这个例子中,fill 函数将整数数组 numbers 中的所有元素都设置为 0

注意事项

  • fill 可以用于各种数据类型,不限于整数。
  • 使用 fill 算法可以有效地初始化或重置容器中的元素。
  • fill 不检查 last 迭代器是否在范围内,使用时应保证范围有效。

通过 fill 算法,可以方便地将容器中的元素设置为指定值,是处理填充操作的常用工具之一。

 下面给出具体代码分析应用过程:

这段代码演示了如何使用 fill 算法来填充整数向量中的所有元素为指定的值。让我来简要解释一下:

  1. 头文件包含

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

    这里包含了使用到的标准库头文件 <numeric><vector><algorithm> 和 <iostream>

  2. 自定义函数对象 myPrint

    class myPrint {
    public:void operator()(int val) {std::cout << val << " ";}
    };
    

    myPrint 是一个重载了函数调用运算符 () 的类,用于在 for_each 算法中打印每个元素的值。

  3. test01 函数

    void test01() {std::vector<int> v;v.resize(10);  // 调整向量大小为10个元素// 使用 fill 算法将向量 v 中的所有元素设置为 100std::fill(v.begin(), v.end(), 100);// 使用 for_each 算法和自定义的 myPrint 函数对象打印向量中的每个元素std::for_each(v.begin(), v.end(), myPrint());std::cout << std::endl;
    }
    
    • 在 test01 函数中,首先创建了一个大小为 10 的整数向量 v
    • 使用 fill 算法将向量 v 中的所有元素设置为 100v.begin() 表示填充的起始位置,v.end() 表示填充的结束位置(不包含在范围内)。
    • 使用 for_each 算法和自定义的 myPrint 函数对象,遍历打印向量 v 中的每个元素值。
  4. main 函数

    int main() {test01();system("pause");return 0;
    }
    

    main 函数调用了 test01 函数,展示了 fill 算法的使用方式和填充后的输出结果。

总结:

  • fill 算法通过指定的值将容器中的指定范围内的所有元素进行填充。
  • 在本例中,fill 将整数向量 v 中的所有元素设置为 100
  • 使用函数对象 myPrint 可以在遍历过程中自定义操作,这里用于打印每个元素。
  • fill 是初始化或重置容器元素的有效工具,能够简化代码并提高可读性。

通过这样的方式,可以快速、方便地对容器中的元素进行填充操作,适用于各种数据类型和填充需求。

#include <numeric>
#include <vector>
#include <algorithm>
class myPrint
{
public:void operator()(int val){cout << val << " ";}
};
void test01()
{vector<int> v;v.resize(10);//填充fill(v.begin(), v.end(), 100);for_each(v.begin(), v.end(), myPrint());cout << endl;
}
int main() {test01();system("pause");return 0;
}

总结  

  • 遍历算法帮助在容器内迭代元素并执行操作,如输出、转换或计算。
  • 算术生成算法用于填充或生成容器的元素,常用于初始化和重置操作。
  • 这些算法能够显著减少代码量并提高可读性,是C++中处理数据和容器操作的强大工具。

这篇关于【C++提高编程-07】----C++ STL常用算法之遍历算法和算术生成算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1067427

相关文章

IDEA自动生成注释模板的配置教程

《IDEA自动生成注释模板的配置教程》本文介绍了如何在IntelliJIDEA中配置类和方法的注释模板,包括自动生成项目名称、包名、日期和时间等内容,以及如何定制参数和返回值的注释格式,需要的朋友可以... 目录项目场景配置方法类注释模板定义类开头的注释步骤类注释效果方法注释模板定义方法开头的注释步骤方法注

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

Python如何自动生成环境依赖包requirements

《Python如何自动生成环境依赖包requirements》:本文主要介绍Python如何自动生成环境依赖包requirements问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录生成当前 python 环境 安装的所有依赖包1、命令2、常见问题只生成当前 项目 的所有依赖包1、

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

springboot项目中常用的工具类和api详解

《springboot项目中常用的工具类和api详解》在SpringBoot项目中,开发者通常会依赖一些工具类和API来简化开发、提高效率,以下是一些常用的工具类及其典型应用场景,涵盖Spring原生... 目录1. Spring Framework 自带工具类(1) StringUtils(2) Coll

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元