目录
2.4 双向迭代器(Bidirectional Iterator)
2.5 随机访问迭代器(Random Access Iterator)
3.2 使用 std::prev 和 std::next 获取前一个和后一个迭代器
1. 迭代器基本概念
迭代器是用于遍历容器元素的对象,就像指针一样。根据功能的不同,迭代器可以分为五种类型:
- 输入迭代器(Input Iterator):只能读取数据,支持单向遍历。
- 输出迭代器(Output Iterator):只能写入数据,支持单向遍历。
- 前向迭代器(Forward Iterator):支持读写操作,可以单向遍历。
- 双向迭代器(Bidirectional Iterator):支持读写操作,可以双向遍历。
- 随机访问迭代器(Random Access Iterator):支持读写操作,可以双向遍历,且支持随机访问。
2. 迭代器类型及其用法示例
2.1 输入迭代器(Input Iterator)
输入迭代器只能用于读取数据,典型的输入迭代器是 std::istream_iterator
。
底层原理:
- 输入迭代器可以读取数据,但不能修改它指向的数据。
- 典型的输入迭代器是
std::istream_iterator
,其底层原理是通过重载operator*
和operator++
来实现读取流中的数据。 - 它通过输入流(如
std::cin
)来读取元素,每次读取一个元素,并将流的位置移动到下一个元素。
特点:
- 只能单向遍历。
- 只能读取一次,不能重复读取。
示例:
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::cout << "Enter integers separated by spaces (Ctrl+D to end): ";
std::istream_iterator<int> input_it(std::cin); // 输入迭代器
std::istream_iterator<int> end_of_stream; // 输入流结束标志
std::vector<int> vec(input_it, end_of_stream); // 从输入流中读取数据并存入向量
std::cout << "You entered: ";
for (const auto& elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
2.2 输出迭代器(Output Iterator)
输出迭代器只能用于写入数据,典型的输出迭代器是 std::ostream_iterator
。
底层原理:
- 输出迭代器用于写入数据,不能读取它指向的数据。
- 典型的输出迭代器是
std::ostream_iterator
,其底层原理是通过重载operator*
,operator++
和operator=
来实现将数据写入到输出流中。 - 它通过输出流(如
std::cout
)来写入元素,每次写入一个元素。
特点:
- 只能单向遍历。
- 每个位置只能写入一次,不能读取已有的数据。
示例:
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
std::cout << "Vector elements: ";
std::ostream_iterator<int> output_it(std::cout, " "); // 输出迭代器
std::copy(vec.begin(), vec.end(), output_it); // 将向量元素写入到标准输出
std::cout << std::endl;
return 0;
}
2.3 前向迭代器(Forward Iterator)
前向迭代器支持读写操作,可以单向遍历。标准库中的 std::forward_list
就是一个前向迭代器的例子。
底层原理:
- 前向迭代器可以读写数据,并且能单向遍历。
- 容器如
std::forward_list
使用前向迭代器,其底层实现通常是一个单向链表。 - 迭代器通过指针或引用来访问链表中的元素,并重载
operator*
和operator++
来遍历。
特点:
- 能读写数据。
- 只能单向遍历。
- 支持多次遍历同一序列。
示例:
#include <iostream>
#include <forward_list>
int main() {
std::forward_list<int> flist = {1, 2, 3, 4, 5};
std::cout << "Forward list elements: ";
for (auto it = flist.begin(); it != flist.end(); ++it) {
std::cout << *it << " "; // 通过解引用操作符访问元素
}
std::cout << std::endl;
return 0;
}
2.4 双向迭代器(Bidirectional Iterator)
双向迭代器支持读写操作,可以双向遍历。典型的双向迭代器有 std::list
和 std::set
。
底层原理:
- 双向迭代器可以读写数据,并能双向遍历。
- 容器如
std::list
和std::set
使用双向迭代器,其底层实现通常是一个双向链表或平衡二叉树。 - 迭代器通过指针或引用访问元素,并重载
operator*
,operator++
,operator--
来遍历。
特点:
- 能读写数据。
- 能前后遍历。
- 支持多次遍历同一序列。
示例:
#include <iostream>
#include <list>
int main() {
std::list<int> lst = {10, 20, 30, 40, 50};
std::cout << "List elements in forward order: ";
for (auto it = lst.begin(); it != lst.end(); ++it) {
std::cout << *it << " "; // 向前遍历并访问元素
}
std::cout << std::endl;
std::cout << "List elements in reverse order: ";
for (auto it = lst.rbegin(); it != lst.rend(); ++it) {
std::cout << *it << " "; // 向后遍历并访问元素
}
std::cout << std::endl;
return 0;
}
2.5 随机访问迭代器(Random Access Iterator)
随机访问迭代器支持读写操作,可以双向遍历,并且支持随机访问。常见的随机访问迭代器有 std::vector
和 std::deque
。
底层原理:
- 随机访问迭代器可以读写数据,能双向遍历,并支持随机访问。
- 容器如
std::vector
和std::deque
使用随机访问迭代器,其底层实现通常是一个动态数组或分段数组。 - 迭代器通过指针操作访问数组中的元素,并重载
operator*
,operator++
,operator--
,operator+
,operator-
,operator[]
来实现遍历和随机访问。
特点:
- 能读写数据。
- 能前后遍历。
- 支持随机访问。
示例:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
std::cout << "Vector elements: ";
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " "; // 向前遍历并访问元素
}
std::cout << std::endl;
std::cout << "Third element: " << vec[2] << std::endl; // 随机访问第三个元素
return 0;
}
3. 常见迭代器的高级操作
3.1 使用 std::advance
移动迭代器
std::advance
可以将迭代器移动指定的步数。
#include <iostream>
#include <vector>
#include <iterator>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin();
std::advance(it, 2); // 将迭代器移动两个位置
std::cout << "Element at position 3: " << *it << std::endl;
return 0;
}
3.2 使用 std::prev
和 std::next
获取前一个和后一个迭代器
std::prev
和 std::next
可以用来获取相邻的迭代器。
#include <iostream>
#include <vector>
#include <iterator>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin();
std::advance(it, 2); // 移动到第三个位置
// 使用 std::prev 获取前一个迭代器
auto prev_it = std::prev(it);
std::cout << "Previous element: " << *prev_it << std::endl;
// 使用 std::next 获取后一个迭代器
auto next_it = std::next(it);
std::cout << "Next element: " << *next_it << std::endl;
return 0;
}
总结
迭代器是 C++ STL 中非常重要的一部分,掌握它们的概念和用法可以大大提高代码的效率和可读性。希望这些详细注释的示例能帮助你更好地理解和应用迭代器。