目 录CONTENT

文章目录

C++ STL:容器-迭代器

TalentQ
2025-08-18 / 0 评论 / 0 点赞 / 7 阅读 / 0 字

1 什么是迭代器?

迭代器(Iterator)是C++ STL(标准模板库)中的一种对象,类似于指针,用于遍历容器(如vector、list、map等)中的元素。迭代器将容器的内部数据结构与访问方式解耦,使我们能以统一的方式访问不同容器的元素。

1.1 迭代器的原理

STL迭代器本质上是一种泛型指针,它通过重载运算符(如*++--等),让用户能够像操作指针一样操作容器中的元素。每种容器会根据自身的数据结构实现适合自己的迭代器类型。

1.2 迭代器的基本操作

  • 解引用:*it,访问迭代器指向的元素。

  • 前进:++it,移动到下一个元素。

  • 后退:--it,移动到前一个元素(仅双向及随机访问迭代器支持)。

  • 比较:it1 == it2,判断是否指向同一元素。

2 STL迭代器分类

2.1 输入迭代器(Input Iterator)

特点

  • 只读访问,每个元素只能访问一次。

  • 支持++*操作。

  • 常用于数据流输入、只读遍历。

代码示例

#include <iostream>
#include <vector>

// 输入迭代器只读遍历vector
void PrintVectorInputIterator(const std::vector<int>& vec) {
  // 使用const_iterator保证只读
  std::vector<int>::const_iterator it = vec.begin();
  for (; it != vec.end(); ++it) {
    std::cout << *it << " ";  // 只能读取,不能修改
  }
  std::cout << std::endl;
}

int main() {
  std::vector<int> numbers = {1, 2, 3, 4, 5};
  PrintVectorInputIterator(numbers);
  return 0;
}

输入迭代器适合数据读取场景,如处理输入流、只读容器遍历。不能进行元素修改,也不支持多次读取同一元素。

2.2 输出迭代器(Output Iterator)

特点

  • 只写访问,每个元素只能写一次。

  • 支持++*操作。

  • 常用于数据流输出、写入算法。

代码示例

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

// 输出迭代器写入vector
void FillVectorOutputIterator(std::vector<int>& vec) {
  // 使用std::fill_n和输出迭代器
  std::fill_n(vec.begin(), vec.size(), 9);  // 将所有元素赋值为9
}

int main() {
  std::vector<int> numbers(5);
  FillVectorOutputIterator(numbers);
  // 使用输出迭代器打印结果
  std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<int>(std::cout, " "));
  std::cout << std::endl;
  return 0;
}

输出迭代器适合写入场景,如输出流、赋值、填充等。不能读取元素值。

2.3 前向迭代器(Forward Iterator)

特点

  • 可读可写,支持单向多次遍历。

  • 支持++*操作。

  • 常用于单向链表。

代码示例

#include <forward_list>
#include <iostream>

// 前向迭代器遍历forward_list
void ForwardListExample() {
  std::forward_list<int> flist = {10, 20, 30, 40};
  std::forward_list<int>::iterator it = flist.begin();
  for (; it != flist.end(); ++it) {
    std::cout << *it << " ";
    *it += 1;  // 支持修改
  }
  std::cout << std::endl;

  // 再次遍历
  for (auto val : flist) {
    std::cout << val << " ";
  }
  std::cout << std::endl;
}

int main() {
  ForwardListExample();
  return 0;
}

前向迭代器适合单向链表等场景,可多次遍历,支持读写操作,但不支持反向移动。

2.4 双向迭代器(Bidirectional Iterator)

特点

  • 可读可写,支持++--双向遍历。

  • 常用于双向链表、集合等。

代码示例

#include <list>
#include <iostream>

// 双向迭代器正反向遍历list
void ListBidirectionalIteratorExample() {
  std::list<int> lst = {5, 10, 15, 20};

  // 正向遍历
  std::list<int>::iterator it = lst.begin();
  for (; it != lst.end(); ++it) {
    std::cout << *it << " ";
    *it *= 2;  // 支持修改
  }
  std::cout << std::endl;

  // 反向遍历
  std::list<int>::reverse_iterator rit = lst.rbegin();
  for (; rit != lst.rend(); ++rit) {
    std::cout << *rit << " ";
  }
  std::cout << std::endl;
}

int main() {
  ListBidirectionalIteratorExample();
  return 0;
}

双向迭代器支持前后移动,适合需要反向遍历的场景,如list、set、map等。

2.5 随机访问迭代器(Random Access Iterator)

特点

  • 可读可写,支持所有指针算术操作(+-[]、比较等)。

  • 常用于数组、vector、deque等。

代码示例

#include <vector>
#include <iostream>

// 随机访问迭代器遍历vector
void VectorRandomAccessIteratorExample() {
  std::vector<int> vec = {7, 14, 21, 28, 35};

  // 随机访问
  for (size_t i = 0; i < vec.size(); ++i) {
    std::cout << vec[i] << " ";
    vec[i] += 1;  // 支持修改
  }
  std::cout << std::endl;

  // 使用迭代器算术
  std::vector<int>::iterator it = vec.begin();
  it += 2;  // 移动到第三个元素
  std::cout << "Third element: " << *it << std::endl;

  // 反向遍历
  for (auto rit = vec.rbegin(); rit != vec.rend(); ++rit) {
    std::cout << *rit << " ";
  }
  std::cout << std::endl;
}

int main() {
  VectorRandomAccessIteratorExample();
  return 0;
}

随机访问迭代器支持高效的索引访问和算术操作,是性能最优的迭代器类型,适合数组、vector等场景。

3 迭代器与其他遍历方式对比

方法

适用范围

性能

可读性

灵活性

安全性

迭代器

所有STL容器

较高

下标访问

支持随机访问容器

范围for循环

所有STL容器

最高

指针遍历

数组、vector

一般

说明

  • 迭代器方式最为通用和安全,推荐优先使用。

  • 范围for循环底层也是通过迭代器实现,适合简单遍历场景。

  • 下标和指针遍历仅适用于支持随机访问的容器,易出错。

4 迭代器的高级用法

4.1 const_iterator

只读迭代器,保证元素不被修改。

#include <vector>
#include <iostream>

// 使用const_iterator只读遍历vector
void PrintConstIterator(const std::vector<int>& vec) {
  for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it) {
    std::cout << *it << " ";  // 不能修改*it
  }
  std::cout << std::endl;
}

4.2 reverse_iterator

反向迭代器,逆序遍历容器。

#include <vector>
#include <iostream>

// 使用reverse_iterator逆序遍历vector
void PrintReverseIterator(const std::vector<int>& vec) {
  for (std::vector<int>::const_reverse_iterator rit = vec.rbegin(); rit != vec.rend(); ++rit) {
    std::cout << *rit << " ";
  }
  std::cout << std::endl;
}

4.3 iterator_traits

萃取迭代器类型信息,用于模板泛型编程。

#include <iterator>
#include <vector>
#include <type_traits>
#include <iostream>

// 泛型函数:判断迭代器是否为随机访问类型
template <typename Iterator>
void CheckRandomAccess(Iterator it) {
  if (std::is_same<
      typename std::iterator_traits<Iterator>::iterator_category,
      std::random_access_iterator_tag>::value) {
    std::cout << "Random access iterator detected." << std::endl;
  } else {
    std::cout << "Not a random access iterator." << std::endl;
  }
}

int main() {
  std::vector<int> v{1,2,3};
  CheckRandomAccess(v.begin());
  return 0;
}

4.4 std::advance和std::distance

通用迭代器操作,支持不同类型迭代器。

#include <vector>
#include <iostream>
#include <iterator>

// advance和distance示例
void IteratorAdvanceDistanceExample() {
  std::vector<int> vec = {10, 20, 30, 40, 50};
  auto it = vec.begin();
  std::advance(it, 3);  // 移动到第4个元素
  std::cout << "Fourth element: " << *it << std::endl;

  auto dist = std::distance(vec.begin(), it);
  std::cout << "Distance from begin to it: " << dist << std::endl;
}

int main() {
  IteratorAdvanceDistanceExample();
  return 0;
}

5 适用场景

  1. 输入迭代器:只读遍历、输入流、算法输入端。

  2. 输出迭代器:只写遍历、输出流、算法输出端。

  3. 前向迭代器:单向链表、多次遍历、读写操作。

  4. 双向迭代器:双向链表、集合、需要反向遍历的场景。

  5. 随机访问迭代器:数组、vector、高效索引、算术操作。

6.实践建议

  • 推荐优先使用迭代器和范围for循环遍历容器,保证代码的通用性和安全性。

  • 根据容器类型选择合适的迭代器,提升性能。

  • 结合STL算法和迭代器,简化代码逻辑,提升开发效率。

  • 使用const_iteratorreverse_iterator等扩展迭代器,满足不同需求。

0

评论区