【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 算法调用普通函数 print01
        for_each(v.begin(), v.end(), print01);
        cout << endl;
    
        // 使用 for_each 算法调用函数对象 print02
        for_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 将数组中所有元素设置为 0
    std::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 中的所有元素设置为 100
        std::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++中处理数据和容器操作的强大工具。
  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一伦明悦

感谢,您的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值