在 C++ 中,迭代算法(Iterative Algorithms)是指通过循环结构(如 for
、while
、do-while
)实现重复计算的算法,其核心是利用迭代器(Iterator)或直接操作容器元素,逐步更新状态直至满足终止条件。C++ 的迭代算法广泛应用于容器遍历、搜索、排序、数值计算等场景,结合标准模板库(STL)中的容器和算法,可实现高效、简洁的代码。以下从迭代器基础、常见迭代算法、实现技巧及示例等方面详细介绍。
一、C++ 迭代器(Iterator)基础
迭代器是 C++ 中用于遍历容器元素的 “指针类” 对象,提供了统一的接口访问不同容器(如 vector
、list
、map
等)的数据。迭代器支持的操作包括:
*it
:解引用,访问当前元素。it++
/it--
:移动到下一 / 前一元素(根据容器特性,可能是双向或单向移动)。it == other_it
/it != other_it
:判断是否指向同一位置。
1. 迭代器类型
- 正向迭代器(Forward Iterator):只能单向移动(如
list<T>::iterator
)。 - 双向迭代器(Bidirectional Iterator):支持前后移动(如
vector<T>::iterator
)。 - 随机访问迭代器(Random Access Iterator):支持跳跃式移动(如
vector<T>::iterator
,类似指针运算it + n
)。
2. 常用容器的迭代器获取
#include <vector>
#include <list>
#include <map>
int main() {
// vector(随机访问迭代器)
std::vector<int> vec = {1, 2, 3};
std::vector<int>::iterator vec_it = vec.begin(); // 指向首元素
std::vector<int>::iterator vec_end = vec.end(); // 指向尾后位置(不包含)
// list(双向迭代器)
std::list<std::string> lst = {"a", "b", "c"};
auto lst_it = lst.begin(); // C++11 可使用 auto 自动推导类型
// map(双向迭代器,键值对为 pair<const Key, Value>)
std::map<int, std::string> m = {{1, "one"}, {2, "two"}};
for (auto it = m.begin(); it != m.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl; // 访问键值对
}
return 0;
}
二、C++ 中常见的迭代算法
C++ 的 STL 提供了大量基于迭代器的算法(定义在 <algorithm>
头文件中),可分为遍历、查找、排序、修改、数值计算等类别。以下是典型示例:
1. 遍历算法:for_each
- 功能:对容器中的每个元素执行指定操作。
- 原型:
template <class InputIt, class UnaryFunction> UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f);
-
#include <algorithm> #include <vector> #include <iostream> void print(int x) { std::cout << x << " "; } int main() { std::vector<int> vec = {10, 20, 30}; std::for_each(vec.begin(), vec.end(), print); // 输出:10 20 30 return 0; }
C++11 Lambda 表达式简化写法:std::for_each(vec.begin(), vec.end(), [](int x) { std::cout << x << " "; });
2. 查找算法:find 和 find_if
find
:查找等于给定值的元素。#include <algorithm> #include <vector> #include <iostream> int main() { std::vector<int> vec = {1, 3, 5, 7}; auto it = std::find(vec.begin(), vec.end(), 5); // 查找值为 5 的元素 if (it != vec.end()) { std::cout << "Found at index: " << (it - vec.begin()) << std::endl; // 输出索引 2 } return 0; }
find_if
:按条件查找元素(通过谓词函数判断)。// 查找第一个大于 4 的元素 auto it = std::find_if(vec.begin(), vec.end(), [](int x) { return x > 4; });
3. 排序算法:sort
- 功能:对容器元素排序(默认升序,可自定义比较规则)。
- 原型:
template <class RandomAccessIterator> void sort(RandomAccessIterator first, RandomAccessIterator last);
- 示例:对
vector
降序排序:#include <algorithm> #include <vector> #include <iostream> bool compare(int a, int b) { return a > b; // 降序 } int main() { std::vector<int> vec = {3, 1, 4, 2}; std::sort(vec.begin(), vec.end(), compare); // 传入比较函数 // 或用 Lambda:std::sort(vec.begin(), vec.end(), [](int a, int b){ return a > b; }); for (int x : vec) { // C++11 范围 for 循环 std::cout << x << " "; // 输出:4 3 2 1 } return 0; }
4. 数值计算:accumulate
- 功能:对容器元素求和(或自定义累加操作)。
- 原型:
template <class InputIt, class T> T accumulate(InputIt first, InputIt last, T init);
- 示例:计算
vector
元素之和:#include <numeric> // accumulate 头文件 #include <vector> #include <iostream> int main() { std::vector<int> vec = {1, 2, 3, 4}; int sum = std::accumulate(vec.begin(), vec.end(), 0); // 初始值为 0 std::cout << "Sum: " << sum << std::endl; // 输出:10 return 0; }
5. 自定义迭代算法:实现斐波那契数列
通过迭代而非递归计算斐波那契数列,避免栈溢出且效率更高。
#include <iostream>
int fibonacci(int n) {
if (n <= 0) return 0;
if (n == 1) return 1;
int a = 0, b = 1, c;
for (int i = 2; i <= n; ++i) {
c = a + b;
a = b;
b = c; // 迭代更新状态
}
return b;
}
int main() {
std::cout << "Fibonacci(10): " << fibonacci(10) << std::endl; // 输出 55
return 0;
}
三、迭代算法的实现技巧
1. 利用范围 for 循环(C++11+)
简化容器遍历,隐藏迭代器细节:
std::vector<int> vec = {1, 2, 3};
for (int x : vec) { // 自动遍历所有元素
std::cout << x << " ";
}
2. 逆向迭代器(Reverse Iterator)
从容器尾部向头部遍历:
std::vector<int> vec = {1, 2, 3};
for (auto it = vec.rbegin(); it != vec.rend(); ++it) { // rbegin() 指向尾元素,rend() 指向头前位置
std::cout << *it << " "; // 输出:3 2 1
}
3. 迭代器失效问题
- 场景:当容器结构改变(如插入、删除元素)时,原有迭代器可能失效(即不再指向有效元素)。
- 解决方案:
- 对
vector
/deque
,插入 / 删除操作后,位于操作点之后的迭代器失效。 - 对
list
/map
/set
,仅当前操作的迭代器失效,其他迭代器保持有效。
std::vector<int> vec = {1, 2, 3, 4}; auto it = vec.begin() + 1; // 指向元素 2 vec.erase(vec.begin()); // 删除首元素,it 失效(因 vector 内存重新分配) // 正确做法:erase 返回新的有效迭代器 it = vec.erase(vec.begin()); // it 指向新的首元素(原元素 2)
- 对
4. 结合 Lambda 表达式
用 Lambda 简化谓词函数或操作逻辑,提高代码简洁性:
// 筛选偶数并存储到新容器
std::vector<int> vec = {1, 2, 3, 4};
std::vector<int> even;
std::copy_if(vec.begin(), vec.end(), std::back_inserter(even), [](int x) {
return x % 2 == 0; // Lambda 作为条件判断
});
四、迭代与递归的性能对比(C++ 场景)
以计算斐波那契数为例:
方法 | 时间复杂度 | 空间复杂度 | C++ 实现风险 |
---|---|---|---|
递归 | O(2n) | O(n) | 栈溢出(n 较大时) |
迭代 | O(n) | O(1) | 无 |
递归实现(低效且危险):
int fib_recursive(int n) {
if (n <= 1) return n;
return fib_recursive(n-1) + fib_recursive(n-2); // 重复计算子问题
}
迭代实现(高效稳定):
int fib_iterative(int n) { /* 见前文示例 */ }
五、总结
C++ 中的迭代算法通过迭代器和循环结构实现,具有高效、可控的特点,尤其在结合 STL 算法时能大幅简化代码。掌握迭代器的类型、容器特性及迭代失效问题,是写出健壮 C++ 代码的关键。实际开发中,优先使用迭代而非递归(除非问题天然适合递归,如树的遍历),以避免栈溢出并提升性能。
核心要点:
- 迭代器是遍历容器的通用工具,需根据容器类型选择合适的迭代器(如随机访问、双向)。
- STL 算法(如
for_each
、sort
)基于迭代器设计,需熟练掌握其用法。 - 注意迭代器失效问题,避免访问无效指针