在C++ STL的vector容器使用中,倒序遍历是一个常见的需求,除了使用下标从后往前访问之外,STL还提供了专门的反向迭代器来完成这个操作,其中rbegin和rend就是最核心的两个反向迭代器接口。

rbegin和rend的基本定义
rbegin和rend是vector容器的成员函数,返回的是反向迭代器类型:
rbegin()返回指向容器最后一个元素的反向迭代器,也就是反向遍历的起始位置rend()返回指向容器第一个元素之前位置的反向迭代器,也就是反向遍历的结束位置
和普通的正向迭代器begin()、end()不同,反向迭代器的移动方向是相反的,当反向迭代器执行++操作时,会向前移动到前一个元素,执行--操作时会向后移动到后一个元素。
使用rbegin和rend倒序遍历vector
下面通过一个简单的示例展示如何使用rbegin和rend完成vector的倒序遍历:
#include <iostream>
#include <vector>
int main() {
// 初始化一个vector
std::vector<int> nums = {1, 2, 3, 4, 5};
// 使用rbegin和rend倒序遍历
std::cout << "倒序遍历结果:" << std::endl;
for (auto it = nums.rbegin(); it != nums.rend(); ++it) {
std::cout << *it << " ";
}
// 输出结果:5 4 3 2 1
std::cout << std::endl;
return 0;
}
上面的代码中,迭代器从nums.rbegin()开始,也就是指向元素5,每次循环执行++it,迭代器会依次指向4、3、2、1,直到迭代器等于nums.rend()时循环结束,就完成了整个vector的倒序遍历。
反向迭代器与正向迭代器的转换
有时候我们可能需要把反向迭代器转换成正向迭代器,这时候可以使用反向迭代器的base()方法,需要注意的是,反向迭代器it的base()返回的是正向迭代器,指向的是it当前指向元素的下一个位置。
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
auto rit = nums.rbegin(); // 指向元素5
auto fit = rit.base(); // 指向元素5的下一个位置,也就是end()
std::cout << "反向迭代器rbegin指向的值:" << *rit << std::endl; // 输出5
if (fit == nums.end()) {
std::cout << "反向迭代器rbegin的base()等于end()" << std::endl;
}
return 0;
}
不同倒序遍历方式的对比
除了使用rbegin和rend之外,我们还可以通过下标从后往前遍历,或者使用反向迭代器适配正向迭代器,下面是几种方式的对比:
| 遍历方式 | 实现复杂度 | 适用场景 |
|---|---|---|
| rbegin+rend反向迭代器 | 低,语法简洁 | 需要标准反向遍历的场景,符合STL迭代器使用习惯 |
| 下标从size-1遍历到0 | 低,容易理解 | 熟悉数组遍历逻辑的开发者,不需要使用迭代器的场景 |
| reverse适配正向迭代器 | 中,需要额外适配 | 需要把正向遍历逻辑复用到反向场景的情况 |
使用注意事项
在使用rbegin和rend的时候需要注意几个问题:
- 反向迭代器不能和正向迭代器直接比较,比如
nums.rbegin() == nums.begin()是错误的,类型不匹配 - 如果vector为空,那么
rbegin() == rend(),遍历循环不会执行,不会出现越界问题 - 修改反向迭代器指向的元素和正向迭代器一样,会直接修改vector中对应位置的元素值
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
auto rit = nums.rbegin();
*rit = 10; // 修改最后一个元素的值
std::cout << "修改后的vector:" << std::endl;
for (int num : nums) {
std::cout << num << " ";
}
// 输出结果:1 2 3 4 10
std::cout << std::endl;
return 0;
}
总的来说,rbegin和rend是C++ vector倒序遍历最标准、最符合STL设计理念的方式,掌握它们的用法可以让我们的代码更规范,也更容易和其他STL容器的遍历逻辑保持一致。