《C++ Primer》导学系列:第 10 章 - 泛型算法

10.2 初识泛型算法

在C++标准库中,泛型算法是用于操作容器元素的一组通用函数。这些算法独立于特定的容器类型,只要容器提供了适当的迭代器,它们就可以作用于任何容器。泛型算法使得代码更加简洁和易于维护。

10.2.1 使用算法的基本步骤

使用泛型算法的一般步骤如下:

  1. 选择合适的算法:根据具体需求选择一个合适的算法。
  2. 提供迭代器范围:算法通常需要两个迭代器参数,表示操作的范围。
  3. 提供额外的参数:有些算法需要额外的参数,如函数对象或初始值。
示例代码
#include <iostream>
#include <vector>
#include <algorithm>

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

    // 使用for_each算法打印每个元素
    std::for_each(vec.begin(), vec.end(), [](int n) {
        std::cout << n << " ";
    });
    std::cout << std::endl;

    // 使用find算法查找某个元素
    auto it = std::find(vec.begin(), vec.end(), 3);
    if (it != vec.end()) {
        std::cout << "Found: " << *it << std::endl;
    } else {
        std::cout << "Not found" << std::endl;
    }

    return 0;
}

10.2.2 非修改算法

非修改算法不改变容器中的元素值,只对元素进行访问操作。常见的非修改算法有:

  • for_each:对范围内的每个元素执行给定的操作。
  • find:在范围内查找第一个等于给定值的元素。
  • count:计算范围内等于给定值的元素个数。
  • accumulate:对范围内的元素进行累加。
示例代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>

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

    // 使用count算法计算3的个数
    int count = std::count(vec.begin(), vec.end(), 3);
    std::cout << "Count of 3: " << count << std::endl;

    // 使用accumulate算法计算所有元素的和
    int sum = std::accumulate(vec.begin(), vec.end(), 0);
    std::cout << "Sum of elements: " << sum << std::endl;

    return 0;
}

10.2.3 修改算法

修改算法会改变容器中的元素值。常见的修改算法有:

  • copy:将范围内的元素复制到另一个范围。
  • transform:对范围内的每个元素应用给定的操作,并将结果保存到另一个范围。
  • replace:将范围内等于某个值的元素替换为另一个值。
  • fill:将范围内的所有元素设置为给定值。
示例代码
#include <iostream>
#include <vector>
#include <algorithm>

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

    // 使用copy算法复制元素
    std::copy(vec.begin(), vec.end(), vec2.begin());
    std::for_each(vec2.begin(), vec2.end(), [](int n) {
        std::cout << n << " ";
    });
    std::cout << std::endl;

    // 使用replace算法将所有3替换为99
    std::replace(vec2.begin(), vec2.end(), 3, 99);
    std::for_each(vec2.begin(), vec2.end(), [](int n) {
        std::cout << n << " ";
    });
    std::cout << std::endl;

    return 0;
}

10.2.4 复杂算法

复杂算法包括排序、搜索和集合操作等。常见的复杂算法有:

  • sort:对范围内的元素进行排序。
  • unique:移除范围内相邻的重复元素。
  • reverse:反转范围内元素的顺序。
  • binary_search:在有序范围内进行二分查找。
示例代码
#include <iostream>
#include <vector>
#include <algorithm>

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

    // 使用sort算法排序
    std::sort(vec.begin(), vec.end());
    std::for_each(vec.begin(), vec.end(), [](int n) {
        std::cout << n << " ";
    });
    std::cout << std::endl;

    // 使用binary_search算法查找元素
    bool found = std::binary_search(vec.begin(), vec.end(), 3);
    std::cout << "3 found: " << std::boolalpha << found << std::endl;

    return 0;
}

重点与难点分析

重点

  1. 理解非修改算法和修改算法的区别:掌握不同算法的用途和使用场景。
  2. 熟悉常用算法的用法:了解常用算法的参数和返回值,能够在实际编程中灵活使用。

难点

  1. 自定义操作的实现:很多算法需要通过函数对象(如lambda表达式)来自定义操作,理解这些函数对象的使用是一个难点。
  2. 迭代器失效问题:在使用修改算法时,要特别注意迭代器失效的问题,尤其是在对容器进行修改的算法中。

练习题解析

  1. 练习10.4:编写一个程序,使用count算法计算一个vector中某个元素出现的次数。
    • 示例代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 3, 3, 5};
    int count = std::count(vec.begin(), vec.end(), 3);
    std::cout << "Count of 3: " << count << std::endl;
    return 0;
}
  1. 练习10.5:编写一个程序,使用replace算法将一个vector中的某个元素替换为另一个值。
    • 示例代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::replace(vec.begin(), vec.end(), 3, 99);
    std::for_each(vec.begin(), vec.end(), [](int n) {
        std::cout << n << " ";
    });
    std::cout << std::endl;
    return 0;
}
  1. 练习10.6:编写一个程序,使用sort算法对一个vector进行排序,并使用binary_search算法在排序后的vector中查找某个元素。
    • 示例代码
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {5, 2, 3, 1, 4};
    std::sort(vec.begin(), vec.end());
    std::for_each(vec.begin(), vec.end(), [](int n) {
        std::cout << n << " ";
    });
    std::cout << std::endl;

    bool found = std::binary_search(vec.begin(), vec.end(), 3);
    std::cout << "3 found: " << std::boolalpha << found << std::endl;
    return 0;
}

总结与提高

本节总结

  1. 了解了泛型算法的基本概念和用途,掌握了非修改算法和修改算法的区别。
  2. 学会了如何选择和使用合适的算法,理解了常用算法的参数和返回值。
  3. 掌握了一些常用的复杂算法的使用方法,并通过示例代码进行了实践。

提高建议

  1. 多练习算法操作:通过编写更多涉及泛型算法的程序,熟悉各种操作方法,提高对泛型算法的使用能力。
  2. 深入理解算法:通过阅读标准库文档和相关书籍,深入理解泛型算法的实现原理和使用场景,提高编写高效代码的能力。
  3. 关注性能优化:在实际项目中,根据具体需求选择最合适的算法和迭代器类型,优化程序性能。

10.3 定制操作

在泛型算法中,许多算法可以通过函数对象(function object)或lambda表达式定制操作行为。这些定制操作使得算法更为灵活和强大。本节将介绍如何使用函数对象和lambda表达式来定制算法操作。

10.3.1 使用函数对象

函数对象是一个定义了operator()的类或结构体的实例。它的作用类似于一个函数,可以在算法中被调用。函数对象比普通函数具有更多的灵活性,因为它们可以在对象中保存状态。

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

struct Print {
    void operator()(int n) const {
        std::cout << n << " ";
    }
};

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

    // 使用函数对象Print打印元素
    std::for_each(vec.begin(), vec.end(), Print());
    std::cout << std::endl;

    return 0;
}

在这个示例中,Print是一个函数对象,它实现了operator(),可以像函数一样被调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AI与编程之窗

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值