首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

【C++ 容器和算法】泛型算法:概述

  • 25-04-25 02:29
  • 3084
  • 10650
blog.csdn.net

目录

一、泛型算法基础概念

1.1 什么是泛型算法?

1.2 核心设计原则

1.3 算法分类体系

1.4 与 STL 容器的关系

二、迭代器:泛型算法的 “钥匙”

2.1 迭代器类型

2.2 迭代器适配器

三、常用泛型算法分类与实战

3.1 非修改型算法(只读)

3.2 修改型算法

3.3 排序与搜索算法

四、算法的高阶应用与优化

4.1 自定义谓词(Predicate)

4.2 性能优化技巧

4.3 C++20 新特性:Ranges 库

五、典型应用场景

5.1 数据处理流水线

5.2 游戏对象管理 

5.3 GUI事件处理

六、 常见误区与解决方案

6.1 迭代器失效问题

6.2 算法与容器不匹配

七、总结

八、参考资料


在 C++ 编程中,算法是处理数据的核心工具。传统算法往往针对特定数据类型设计,缺乏复用性;而泛型算法(Generic Algorithms)通过模板技术实现类型无关化,可适配多种容器与数据类型,极大提升代码通用性与效率。

一、泛型算法基础概念

1.1 什么是泛型算法?

泛型算法是一类基于模板的通用函数,不依赖具体数据类型,而是通过迭代器(Iterator)操作容器元素。例如,std::find用于查找元素,既可作用于vector,也能适配list,只需传递对应容器的迭代器即可。具有以下显著特点:

  • 类型无关性:可作用于各种容器类型

  • 通用接口:统一使用迭代器作为访问接口

  • 高效实现:经过深度优化的经典算法实现

  • 可组合性:算法之间可灵活组合使用

1.2 核心设计原则

  • 类型无关性:通过模板参数推导数据类型(如T)。
  • 迭代器抽象:算法仅依赖迭代器接口(如*it取值、++it移动),不关心容器内部结构。
  • 复用性:一套算法适配多种容器(vector、list、deque等)。

1.3 算法分类体系

STL算法可分为六大类:

分类代表算法特性说明
非修改序列算法find, count, for_each不改变容器内容
修改序列算法copy, replace, reverse直接修改容器元素
排序相关算法sort, stable_sort元素排序和重组
数值算法accumulate, inner_product数学计算操作
集合算法set_union, set_difference集合运算
堆算法make_heap, push_heap堆结构操作

1.4 与 STL 容器的关系

泛型算法是 C++ 标准模板库(STL)的重要组成部分,与容器紧密协作:

  • 容器提供数据存储:如vector管理动态数组。
  • 算法提供操作逻辑:如std::sort对容器元素排序。
  • 迭代器架起桥梁:通过迭代器范围[first, last)指定算法作用区间(last指向末尾后一位)。

图示:泛型算法、容器与迭代器的协作关系

二、迭代器:泛型算法的 “钥匙”

2.1 迭代器类型

C++ 定义了 5 类迭代器,算法依需求选用:

类型

功能特性

典型应用算法

输入迭代器

单向读取(*it、++it)

std::find、std::for_each

输出迭代器

单向写入(*it = value)

std::copy

前向迭代器

单向读写(输入 + 输出功能结合)

std::list专用算法

双向迭代器

双向读写(--it支持逆向)

std::reverse

随机访问迭代器

随机定位(it[n]、it += n)

std::sort、std::binary_search

2.2 迭代器适配器

  • std::back_inserter:自动适配push_back,简化元素插入。
  • std::istream_iterator/std::ostream_iterator:绑定流对象,实现文件 / 控制台数据读写。

示例:使用std::back_inserter向vector插入元素

  1. #include
  2. #include
  3. #include
  4. using namespace std;
  5. int main() {
  6. vector<int> v;
  7. auto inserter = back_inserter(v); // 创建插入迭代器
  8. *inserter = 10; // 等效于v.push_back(10)
  9. *inserter = 20;
  10. for (int x : v) cout << x << " "; // 输出: 10 20
  11. return 0;
  12. }

三、常用泛型算法分类与实战

3.1 非修改型算法(只读)

  • 查找类:std::find、std::count
  • 判断类:std::all_of、std::any_of
  • 统计类:std::accumulate

示例:统计容器中偶数个数

  1. #include
  2. #include
  3. #include
  4. using namespace std;
  5. void doubleValue(int& x) { x *= 2; }
  6. int main() {
  7. vector<int> v = {1, 2, 3};
  8. std::for_each(v.begin(), v.end(), doubleValue);
  9. for (int x : v) cout << x << " "; // 输出: 2 4 6
  10. return 0;
  11. }

3.2 修改型算法

  • 变换类:std::transform
  • 替换类:std::replace
  • 删除类:std::remove(需结合容器erase真正删除)

示例:将容器元素翻倍

  1. #include
  2. #include
  3. #include
  4. using namespace std;
  5. void doubleValue(int& x) { x *= 2; }
  6. int main() {
  7. vector<int> v = {1, 2, 3};
  8. std::for_each(v.begin(), v.end(), doubleValue);
  9. for (int x : v) cout << x << " "; // 输出: 2 4 6
  10. return 0;
  11. }

3.3 排序与搜索算法

  • 排序:std::sort(快速排序)、std::stable_sort(稳定排序)
  • 二分查找:std::binary_search

示例:自定义比较函数排序结构体

  1. #include
  2. #include
  3. #include
  4. using namespace std;
  5. struct Point {
  6. int x, y;
  7. };
  8. bool compareByX(const Point& a, const Point& b) {
  9. return a.x < b.x;
  10. }
  11. int main() {
  12. vector points = {{3, 4}, {1, 2}, {2, 3}};
  13. std::sort(points.begin(), points.end(), compareByX);
  14. for (const auto& p : points) {
  15. cout << "(" << p.x << ", " << p.y << ") ";
  16. }
  17. return 0;
  18. }

四、算法的高阶应用与优化

4.1 自定义谓词(Predicate)

通过 lambda 表达式或函数对象定制算法逻辑,如std::sort的比较规则、std::find_if的查找条件。

4.2 性能优化技巧

  • 避免不必要的拷贝:使用std::move减少元素复制开销。
  • 选择合适的容器与算法:例如,std::list不适合std::sort(需随机访问迭代器),应改用std::list::sort。

4.3 C++20 新特性:Ranges 库

Ranges 库简化算法调用,支持惰性求值(延迟计算)。例如:

  1. #include
  2. #include
  3. #include
  4. using namespace std;
  5. int main() {
  6. vector<int> v = {1, 2, 3, 4, 5};
  7. auto result = v | views::filter([](int x) { return x % 2 == 0; }) | views::transform([](int x) { return x * 2; });
  8. for (int x : result) cout << x << " "; // 输出: 4 8
  9. return 0;
  10. }

五、典型应用场景

5.1 数据处理流水线

  1. // 读取数据 -> 过滤 -> 变换 -> 统计 -> 输出
  2. ifstream input("data.txt");
  3. vector raw_data;
  4. // 读取阶段
  5. Data temp;
  6. while (input >> temp) {
  7. raw_data.push_back(temp);
  8. }
  9. // 过滤阶段
  10. auto new_end = std::remove_if(raw_data.begin(), raw_data.end(),
  11. [](const Data& d){ return d.value < 0; });
  12. raw_data.erase(new_end, raw_data.end());
  13. // 变换阶段
  14. std::transform(raw_data.begin(), raw_data.end(), raw_data.begin(),
  15. [](Data d){ d.value *= 2; return d; });
  16. // 统计阶段
  17. int count = std::count_if(raw_data.begin(), raw_data.end(),
  18. [](const Data& d){ return d.category == "A"; });
  19. // 输出阶段
  20. std::for_each(raw_data.begin(), raw_data.end(),
  21. [](const Data& d){ cout << d << endl; });

5.2 游戏对象管理 

  1. class GameObject {
  2. public:
  3. bool isActive() const { return m_active; }
  4. void update() { /* ... */ }
  5. private:
  6. bool m_active = true;
  7. };
  8. vector objects;
  9. // 批量更新活跃对象
  10. std::for_each(objects.begin(), objects.end(),
  11. [](GameObject& obj){ if (obj.isActive()) obj.update(); });
  12. // 移除所有非活跃对象
  13. auto new_end = std::remove_if(objects.begin(), objects.end(),
  14. [](const GameObject& obj){ return !obj.isActive(); });
  15. objects.erase(new_end, objects.end());

5.3 GUI事件处理

  1. vector event_queue;
  2. // 处理鼠标事件
  3. auto it = std::remove_if(event_queue.begin(), event_queue.end(),
  4. [](const Event& e){
  5. return e.type != MOUSE_MOVE &&
  6. e.type != MOUSE_CLICK;
  7. });
  8. event_queue.erase(it, event_queue.end());
  9. // 分派事件
  10. std::for_each(event_queue.begin(), event_queue.end(),
  11. [](const Event& e){
  12. switch(e.type) {
  13. case MOUSE_MOVE: handle_move(e); break;
  14. case MOUSE_CLICK: handle_click(e); break;
  15. }
  16. });

六、 常见误区与解决方案

6.1 迭代器失效问题

  • 场景:容器插入 / 删除元素后,原有迭代器可能失效。
  • 解决:使用插入迭代器(如back_inserter)或及时更新迭代器。

6.2 算法与容器不匹配

例如:对list使用std::sort会编译错误,应改用list::sort。

误用std::remove

  1. vector<int> v = {1, 2, 2, 3};
  2. v.erase(std::remove(v.begin(), v.end(), 2), v.end()); // 移除所有值为2的元素

std::remove仅逻辑删除(移动元素),需配合erase真正释放空间:

七、总结

泛型算法通过模板与迭代器的结合,实现了高度抽象与复用,是 C++ 高效编程的基石。从基础查找排序到复杂自定义逻辑,掌握算法的使用场景与迭代器适配技巧,能大幅提升代码质量。结合 C++ 新特性(如 Ranges 库),更可进一步简化开发流程。后续可深入探索分区算法、堆操作等进阶内容,解锁更多编程可能。

八、参考资料

  •  《C++ Primer(第 5 版)》这本书是 C++ 领域的经典之作,对 C++ 的基础语法和高级特性都有深入讲解。
  • 《Effective C++(第 3 版)》书中包含了很多 C++ 编程的实用建议和最佳实践。
  • 《C++ Templates: The Complete Guide(第 2 版)》该书聚焦于 C++ 模板编程,而using声明在模板编程中有着重要应用,如定义模板类型别名等。
  • C++ 官方标准文档:C++ 标准文档是最权威的参考资料,可以查阅最新的 C++ 标准(如 C++11、C++14、C++17、C++20 等)文档。例如,ISO/IEC 14882:2020 是 C++20 标准的文档,可从相关渠道获取其详细内容。
注:本文转载自blog.csdn.net的byte轻骑兵的文章"https://blog.csdn.net/weixin_37800531/article/details/147155772"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

113
数据结构与算法
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top