c++:迭代器(Iterator)

发布于:2025-05-09 ⋅ 阅读:(11) ⋅ 点赞:(0)

目录

🚪什么是迭代器?

🔧 迭代器的本质

为什么不用普通数组或下标?

STL容器的迭代器并不是共用一个类型!

迭代器的类型(Iterator Categories)

📦 常见容器的迭代器类型

✅ 迭代器最常用的动作

🚸 初学者推荐写法:使用 auto 和 范围for


🚪什么是迭代器?

迭代器 = “智能指针”,用来一个一个地访问容器中的元素

你可以想象迭代器像是容器中的“手指”或“光标”:

  • 指着某个元素

  • 可以向前走(甚至有些还能往后走)

  • 能取出或修改元素

 示例对比:用数组 vs 用迭代器

int arr[] = {10, 20, 30};
for (int i = 0; i < 3; i++) {
    std::cout << arr[i];
}

改成 vector + 迭代器写法: 

std::vector<int> v = {10, 20, 30};
for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
    std::cout << *it;
}
  • v.begin():返回指向第一个元素的迭代器

  • v.end():返回“超出最后一个元素的下一个位置”的迭代器

  • *it:表示取出当前指向的元素

  • ++it:移动到下一个元素

🔧 迭代器的本质

迭代器是一个类类型(不是基本类型)

虽然它看起来像指针(用 *it 解引用,用 ++it 移动),但它本质上是一个 C++ 类对象,封装了访问容器内部元素的逻辑。

🚩你可以这样理解:

指针 迭代器
访问数组元素 访问容器元素
*ptr 获取值 *it 获取元素
是内建类型 是类类型(有重载了 *, ++, == 等操作符)

🎓 举个例子看看类型:

std::vector<int> v = {1, 2, 3};
auto it = v.begin();
  • it 实际的类型是 std::vector<int>::iterator

  • 你可以打印:

std::cout << typeid(it).name() << std::endl;

输出可能是:__gnu_cxx::__normal_iterator<int*, std::vector<int>>

🔍 它是一个内部实现的类,封装了指针行为,但比裸指针更安全、更通用。


为什么不用普通数组或下标?

STL 有很多不同的容器:链表、哈希表、红黑树……
它们里面的元素并不一定支持下标 [],但每种容器都提供了“迭代器”接口,你可以统一方式遍历。

容器 支持下标? 支持迭代器?
vector
list
set
map

每个容器都有自己专属的迭代器类型,std::vector<T>::iterator  这种写法是访问这个类型的一种方式。

STL容器的迭代器并不是共用一个类型!

容器类型 对应迭代器类型
std::vector<T> std::vector<T>::iterator
std::list<T> std::list<T>::iterator
std::set<T> std::set<T>::iterator
std::map<K,V> std::map<K,V>::iterator
std::vector<int>::iterator it;  // vector 的迭代器
std::list<double>::iterator it2;  // list 的迭代器

为什么不统一一个 iterator 类型呢?
👉 因为不同容器的内部结构不同(如数组 vs 链表 vs 红黑树),它们的迭代器行为也不同。比如:

  • vector 支持随机访问 (it + 3)

  • list 只支持前后移动(++it, --it

 

迭代器的类型(Iterator Categories)

STL 根据迭代器的能力,把迭代器分成 五类,从弱到强如下:

类型 功能 示例容器
InputIterator 单向只读 istream_iterator
OutputIterator 单向只写 ostream_iterator
ForwardIterator 单向读写 forward_list
BidirectionalIterator 可双向移动 list, set, map
RandomAccessIterator 支持随机访问 it+n, it1-it2 vector, deque, array

💡 STL 算法会根据迭代器的种类选择最优的操作方式。

 

📦 常见容器的迭代器类型

容器 支持的迭代器类型
vector, deque, array 随机访问迭代器(RandomAccessIterator)
list 双向迭代器(BidirectionalIterator)
forward_list 单向迭代器(ForwardIterator)
set, map, multimap, multiset 双向迭代器(BidirectionalIterator)
unordered_map, unordered_set 同样为双向迭代器

随机访问迭代器(vector): 

std::vector<int> v = {1, 2, 3, 4};
auto it = v.begin();
std::cout << *(it + 2);  // 输出:3

 双向迭代器(list):

std::list<int> l = {1, 2, 3};
auto it = l.end(); --it;
std::cout << *it;  // 输出:3

 单向迭代器(forward_list):

std::forward_list<int> fl = {1, 2, 3};
auto it = fl.begin();
++it;  // 可以前进,但不能后退


✅ 迭代器最常用的动作

操作 含义
it = container.begin() 取得起始位置的迭代器
it != container.end() 判断是否结束
++it 移动到下一个元素
*it 获取当前指向的元素
std::vector<int> nums = {5, 10, 15};
for (auto it = nums.begin(); it != nums.end(); ++it) {
    std::cout << *it << " ";
}
操作 说明
--it 移动到上一个元素(双向或更强迭代器)
it == it2, it != it2 比较两个迭代器
it + n, it - n 随机访问(仅支持随机访问迭代器)
std::distance(it1, it2) 两个迭代器之间的距离
std::advance(it, n) 将迭代器移动 n 个位置(支持不同迭代器类型)

🚸 初学者推荐写法:使用 auto范围for

从 C++11 开始,可以让写法更简单!

✅ 用 auto 简化迭代器声明:

for (auto it = nums.begin(); it != nums.end(); ++it)

✅ 更简单的方法:范围for(推荐):

范围 for 是 C++11 引入的一种简洁写法,用于遍历容器或数组。它让你不需要写迭代器、不需要用下标,直接访问每一个元素。 

for (元素类型 变量名 : 容器) {
    // 使用变量名代表当前元素
}

传统写法(使用迭代器): 

std::vector<int> v = {1, 2, 3, 4};
for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
    std::cout << *it << "\n";
}

 范围 for 写法:

std::vector<int> v = {1, 2, 3, 4};
for (int x : v) {
    std::cout << x << "\n";
}

 范围 for 背后的原理:

for (auto it = v.begin(); it != v.end(); ++it) {
    int x = *it;
    ...
}

所以它仍然依赖迭代器,只不过帮你“自动写好了”。


网站公告

今日签到

点亮在社区的每一天
去签到