【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

相关文章

MybatisGenerator文件生成不出对应文件的问题

《MybatisGenerator文件生成不出对应文件的问题》本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成... 目录MyBATisGenerator 文件生成不出对应文件先在项目结构里引入“targetProje

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

Python使用qrcode库实现生成二维码的操作指南

《Python使用qrcode库实现生成二维码的操作指南》二维码是一种广泛使用的二维条码,因其高效的数据存储能力和易于扫描的特点,广泛应用于支付、身份验证、营销推广等领域,Pythonqrcode库是... 目录一、安装 python qrcode 库二、基本使用方法1. 生成简单二维码2. 生成带 Log

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南

《Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南》在日常数据处理工作中,我们经常需要将不同Excel文档中的数据整合到一个新的DataFrame中,以便进行进一步... 目录一、准备工作二、读取Excel文件三、数据叠加四、处理重复数据(可选)五、保存新DataFram

SpringBoot生成和操作PDF的代码详解

《SpringBoot生成和操作PDF的代码详解》本文主要介绍了在SpringBoot项目下,通过代码和操作步骤,详细的介绍了如何操作PDF,希望可以帮助到准备通过JAVA操作PDF的你,项目框架用的... 目录本文简介PDF文件简介代码实现PDF操作基于PDF模板生成,并下载完全基于代码生成,并保存合并P

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

Java 枚举的常用技巧汇总

《Java枚举的常用技巧汇总》在Java中,枚举类型是一种特殊的数据类型,允许定义一组固定的常量,默认情况下,toString方法返回枚举常量的名称,本文提供了一个完整的代码示例,展示了如何在Jav... 目录一、枚举的基本概念1. 什么是枚举?2. 基本枚举示例3. 枚举的优势二、枚举的高级用法1. 枚举