Day 30 C++ STL 常用算法(上)

算法概述

  • 算法主要是由头文件<algorithm> <functional> <numeric>组成。
  • <algorithm>头文件是STL中最大的头文件之一,它提供了一系列的算法操作,包括比较、交换、查找、遍历、复制、修改等等。

排序算法:sort()、stable_sort()、partial_sort()等。
查找算法:find()、find_if()、binary_search()等。
数值算法:accumulate()、inner_product()、adjacent_difference()等。
复制和移动算法:copy()、move()、copy_if()等。
修改算法:transform()、replace()、fill()、generate()等。
遍历算法:for_each()、count()、count_if()等。
合并和重排算法:merge()、reverse()、rotate()等。

  • <numeric>头文件相对较小,主要包括一些简单的数学运算函数。这些函数通常应用于序列上,例如数组或容器。

累加算法:accumulate(),实现对序列中元素进行累加求和。
内积算法:inner_product(),计算两个序列的内积。
部分和算法:partial_sum(),计算序列的部分和。
邻接差算法:adjacent_difference(),计算序列每对相邻元素的差值。
乘积算法:reduce(),计算序列中元素的乘积。

  • <functional>头文件定义了一些模板类,用于声明函数对象。函数对象是一种类对象,可以像函数一样调用。

算术类:plus、minus、multiplies、divides等。
比较类:equal_to、greater、less、not_equal_to等。
逻辑类:logical_and、logical_or、logical_not等。
一元函数适配器:negate、bind1st、bind2nd等。
二元函数适配器:not1、not2、compose1、compose2等。

这些函数对象类可以与算法和其他STL组件一起使用,以提供更灵活和可定制的功能。

常用遍历算法

for_each——实现遍历容器

实际开发中是最常用的遍历算法

函数原型
  • for_each(iterator beg, iterator end, _func);

参数说明

  • beg:要遍历的容器的起始迭代器。
  • end:要遍历的容器的结束迭代器,指向容器中最后一个元素的下一个位置。
  • _func:要在每个元素上执行的函数或函数对象。该函数或函数对象对传入的元素进行处理。
示例
#include <iostream>
#include <vector>
#include <algorithm>

void printNum(int num) {
    std::cout << num << " ";
}

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

    // 使用 for_each() 遍历容器中的元素,并调用 printNum() 函数输出每个元素
    std::for_each(nums.begin(), nums.end(), printNum);
    // 输出结果: 1 2 3 4 5
    return 0;
}

transform——搬运容器到另一个容器中

transform() 函数会遍历源容器中的元素,并将每个元素传递给 _func 进行转换操作,然后将转换结果存储到目标容器中。

函数原型
  • transform(iterator beg1, iterator end1, iterator beg2, _func);

//beg1 源容器开始迭代器

//end1 源容器结束迭代器

//beg2 目标容器开始迭代器

//_func 函数或者函数对象

注意

搬运的目标容器必须要提前开辟空间,否则无法正常搬运

示例
#include <iostream>
#include <vector>
#include <algorithm>

int square(int x) {
    return x * x;
}

int main() {
    std::vector<int> nums = {1, 2, 3, 4, 5};
    std::vector<int> squares(nums.size()); // 目标容器

    // 使用 transform() 算法将 nums 中的每个元素平方,并将结果存储到 squares 容器中
    std::transform(nums.begin(), nums.end(), squares.begin(), square);

    // 输出转换后的结果
    for (int num : squares) {
        std::cout << num << " ";
    }
    // 输出结果: 1 4 9 16 25
    return 0;
}

常用查找算法

算法简介:

  • find //查找元素
  • find_if //按条件查找元素
  • adjacent_find //查找相邻重复元素
  • binary_search //二分查找法
  • count //统计元素个数
  • count_if //按条件统计元素个数

find——查找指定元素

按值查找元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()

函数原型
  • find(iterator beg, iterator end, value);

    // beg 开始迭代器

    // end 结束迭代器

    // value 查找的元素

示例
#include <iostream>
#include <vector>
#include <algorithm>

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

    // 使用 find() 算法在 nums 容器中查找元素值为 3 的元素
    auto it = std::find(nums.begin(), nums.end(), 3);

    // 判断是否找到了匹配的元素
    if (it == nums.end() && *it == num) {
        std::cout << "未找到元素值为 3 的元素" << std::endl;
    } else {
        std::cout << "找到了元素值为 3 的元素" << std::endl;
    }
    return 0;
}

在上面的例子中,我们定义了一个 nums 容器,并使用 find() 算法在容器中查找值为 3 的元素。

如果找到了匹配的元素,find() 函数将返回指向该元素的迭代器,并将其赋值给变量 it。我们可以通过判断 it 是否等于容器的结束迭代器 nums.end() 来确定是否找到了匹配的元素。

最后,根据判断结果输出相应的信息。

如果在上述示例中,nums 容器中存在值为 3 的元素,那么输出将是 “找到了元素值为 3 的元素”;如果不存在值为 3 的元素,输出将是 “未找到元素值为 3 的元素”。


find_if—— 查找符合条件的元素

函数原型
  • find_if(iterator beg, iterator end, _Pred);

    // 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

    // beg 开始迭代器

    // end 结束迭代器

    // _Pred 函数或者谓词(返回bool类型的仿函数)(用于确定元素是否满足条件的谓词函数对象。)

示例
#include <algorithm>
#include <vector>
#include <string>
//内置数据类型
class GreaterFive
{
public:
	bool operator()(int val)
	{
		return val > 5;
	}
};

void test01() {
	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(i + 1);
	}
	vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
	if (it == v.end()) {
		cout << "没有找到!" << endl;
	}
	else {
		cout << "找到大于5的数字:" << *it << endl;
	}
}

//自定义数据类型
class Person {
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
public:
	string m_Name;
	int m_Age;
};

class Greater20
{
public:
	bool operator()(Person &p)
	{
		return p.m_Age > 20;
	}

};

void test02() {
	vector<Person> v;
	//创建数据
	Person p1("aaa", 10);
	Person p2("bbb", 20);
	Person p3("ccc", 30);
	Person p4("ddd", 40);

	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);

	vector<Person>::iterator it = find_if(v.begin(), v.end(), Greater20());
	if (it == v.end())
	{
		cout << "没有找到!" << endl;
	}
	else
	{
		cout << "找到姓名:" << it->m_Name << " 年龄: " << it->m_Age << endl;
	}
}

int main() {

	//test01();

	test02();

	system("pause");

	return 0;
}

adjacent_find——查找相邻重复元素

函数原型
  • adjacent_find(iterator beg, iterator end);

    // 查找相邻重复元素,返回相邻元素的第一个位置的迭代器

    // 找不到则返回最后一个位置的迭代器

    // beg 开始迭代器

    // end 结束迭代器

注意

面试题中如果出现查找相邻重复元素,记得用STL中的adjacent_find算法

示例
#include <algorithm>
#include <vector>

void test01()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(5);
	v.push_back(2);
	v.push_back(4);
	v.push_back(4);
	v.push_back(3);

	//查找相邻重复元素
	vector<int>::iterator it = adjacent_find(v.begin(), v.end());
	if (it == v.end()) {
		cout << "找不到!" << endl;
	}
	else {
		cout << "找到相邻重复元素为:" << *it << endl;
	}
}

binary_search——查找指定元素是否存在

函数原型
  • bool binary_search(iterator beg, iterator end, value);

    // 查找指定的元素,查到 返回true 否则false

    // 注意: 在无序序列中不可用

    // beg 开始迭代器

    // end 结束迭代器

    // value 查找的元素

配合二分查找法查找效率很高,值得注意的是查找的容器中元素必须的有序序列

示例
#include <algorithm>
#include <vector>

void test01()
{
	vector<int>v;

	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	//二分查找
	bool ret = binary_search(v.begin(), v.end(),2);
	if (ret)
	{
		cout << "找到了" << endl;
	}
	else
	{
		cout << "未找到" << endl;
	}
}

int main() {

	test01();

	system("pause");

	return 0;
}

count——统计元素个数

函数原型
  • count(iterator beg, iterator end, value);

    // 统计元素出现次数

    // beg 开始迭代器

    // end 结束迭代器

    // value 统计的元素

注意: 统计自定义数据类型时候,需要配合重载 operator==

示例
#include <iostream>
#include <algorithm>
#include <vector>

struct Person {
    std::string name;
    int age;

    // 重载 operator== 运算符
    bool operator==(const Person& other) const {
        return name == other.name && age == other.age;
    }
};

int main() {
    std::vector<Person> people = {
        {"Alice", 25},
        {"Bob", 30},
        {"Alice", 25},
        {"Charlie", 35},
        {"Alice", 25}
    };

    Person target = {"Alice", 25};
    int count = std::count(people.begin(), people.end(), target);

    std::cout << "The person " << target.name << " with age " << target.age << " appears " << count << " times." << std::endl;

    return 0;
}

在这个例子中,我们定义了一个结构体Person,其中包含姓名(name)和年龄(age)两个成员变量。然后,我们重载了operator==运算符,以便能够比较两个Person对象是否相等。

在main函数中,我们创建了一个people向量,其中包含了几个Person对象。我们想要统计具有姓名为"Alice"且年龄为25的人出现的次数。使用std::count函数,我们传入了people的迭代器范围以及目标对象target,并得到了出现次数。最后,输出结果即为该人物出现的次数。

count_if——统计符合条件的元素个数

函数原型
  • count_if(iterator beg, iterator end, _Pred);

    // 按条件统计元素出现次数

    // beg 开始迭代器

    // end 结束迭代器

    // _Pred 谓词

示例
#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> numbers = {5, 15, 8, 12, 20, 30, 7, 10};
    
    // 统计大于10的元素个数
    int count = std::count_if(numbers.begin(), numbers.end(), [](int num) {
        return num > 10;
    });
    
    std::cout << "The number of elements greater than 10: " << count << std::endl;

    return 0;
}

输出
The number of elements greater than 10: 5


在上面的代码中,我们定义了一个整数向量numbers,其中包含了一些整数。然后,我们使用std::count_if函数来统计大于10的元素个数。为了指定统计条件,我们传递了一个匿名的Lambda表达式作为谓词参数。Lambda表达式的函数体是return num > 10;,它表示当传入的num大于10时返回true,否则返回false。

总结:按值统计用count,按条件统计用count_if

猜你喜欢

转载自blog.csdn.net/m0_74921567/article/details/132256712