当前位置: 首页 > news >正文

深入理解C++迭代器:让你的C++代码更加灵活

C++迭代器:更加优雅的容器操作方式

  • 引言
  • C++迭代器简介
    • a. 迭代器的定义
    • b. 迭代器的作用
    • c. 迭代器与指针的区别
  • 迭代器分类
    • a. 输入迭代器(Input Iterator)
    • b. 输出迭代器(Output Iterator)
    • c. 前向迭代器(Forward Iterator)
    • d. 双向迭代器(Bidirectional Iterator)
    • e. 随机访问迭代器(Random Access Iterator)
    • 五类迭代器在C++标准库中的典型应用
  • STL中的迭代器
    • a. 容器和迭代器的关系
    • b. 各种容器的迭代器类型
      • i. 顺序容器(vector、list、deque)
      • ii. 关联容器(set、map、multiset、multimap)
      • iii. 无序关联容器(unordered_set、unordered_map、unordered_multiset、unordered_multimap)
  • 常用的迭代器操作和STL算法的应用实例
    • 1. 迭代器操作
    • 2. STL算法实例
      • a. find(查找)
      • b. sort(排序)
      • c. count(计数)
  • 迭代器操作
    • a. 常用操作
    • b. 增加和减少迭代器
    • c. 读取和修改元素值
    • d. 迭代器间的关系比较
    • e. 迭代器适配器(如反向迭代器、插入迭代器等)
      • 反向迭代器
      • 插入迭代器
  • 迭代器失效问题
    • a. 什么是迭代器失效
    • b. 迭代器失效的原因
    • c. 如何避免迭代器失效
  • C++11及以后版本中的新特性
    • a. 范围for循环
    • b. auto关键字在迭代器中的应用
    • c. 基于范围的迭代器适配器
  • 实际应用举例
    • a. 使用迭代器实现常见算法
      • i. 查找
      • ii. 排序
      • iii. 复制
      • iv. 删除
    • b. 迭代器在自定义数据结构中的应用
  • 总结
    • a. 回顾本文讨论的主要内容
    • b. C++迭代器在编程中的重要性
    • c. 鼓励读者深入学习和实践

引言

在现代编程中,迭代器是一种非常重要且广泛应用的编程范式。它们为我们提供了一种通用的方法来访问和操作各种数据结构中的元素。C++是一种支持面向对象编程、泛型编程和过程编程的高性能编程语言。在C++中,迭代器在标准库(STL)中的容器和算法的实现中发挥着至关重要的作用。本文将介绍C++迭代器的基本概念、分类、操作和实际应用,并探讨C++11及以后版本中迭代器的新特性。

本文的目的是帮助读者理解C++迭代器的原理和使用方法,以便在编程实践中更有效地使用这一强大的工具。本文将首先简要介绍迭代器的概念和作用,然后详细讨论迭代器的分类和STL中的各种迭代器类型。接着,我们将介绍迭代器的基本操作,如增加和减少迭代器、读取和修改元素值等。此外,本文还将讨论迭代器失效的问题,并提供相应的解决方法。在后续部分,我们将探讨C++11及以后版本中的迭代器新特性,如范围for循环、auto关键字等。最后,我们将通过实际应用举例来演示如何使用迭代器实现常见算法和自定义数据结构。

在阅读本文后,您将对C++迭代器有一个全面的了解,并能在实际编程中灵活应用这一重要概念。让我们开始吧!


C++迭代器简介

迭代器(iterator)是一种检查容器内元素并遍历元素的数据类型。
C++更趋向于使用迭代器而不是下标操作,因为标准库为每一种标准容器(如vector)定义了一种迭代器类型,而只用少数容器(如vector)支持下标操作访问容器元素。

a. 迭代器的定义

每种容器都定义了自己的迭代器类型,如vector:

vector<int>::iterator    iter;    //定义一个名为iter的变量

每种容器都定义了一对名为begin和end的成员函数,用于返回迭代器。

下面对迭代器进行初始化操作:

vector<int> ivec;
vector<int>::iterator iter1 = ivec.begin(); //将迭代器iter1初始化为指向ivec容器的第一个元素vector<int>::iterator iter2 = ivec.end(); //将迭代器iter2初始化为指向ivec容器的最后一个元素的下一个位置

注意:

  • end并不指向容器的任何元素,而是指向容器的最后元素的下一位置,称为超出末端迭代器(past-the-end iterator)。
  • 如果vector为空,则begin返回的迭代器和end返回的迭代器相同。
    一旦像上面这样定义和初始化迭代器,就相当于把该迭代器和容器进行了某种关联,就像把一个指针初始化为指向某一空间地址一样。

b. 迭代器的作用

迭代器的主要作用有以下几点:

  • 提供一种通用的访问和操作容器中元素的方法,使得算法可以独立于容器类型来实现。
  • 对不同容器类型提供统一的接口,简化了编程过程。
  • 实现容器和算法之间的解耦,使得算法可以高度复用。

c. 迭代器与指针的区别

迭代器和指针在很多方面具有相似性,但它们之间也有一些关键区别:

  1. 指针是一种低级别的数据结构,直接与内存地址相关;而迭代器是一种抽象概念,可以通过类模板实现,不一定与内存地址直接相关。
  2. 迭代器可以支持更丰富的操作,例如在关联容器和无序关联容器中,迭代器可以在插入和删除元素时保持稳定;而指针可能会失效。
  3. 迭代器可以应对更加复杂的数据结构,如链表和树等;而指针更适用于连续的内存空间,如数组。
  4. 迭代器可以提供更严格的类型检查,有助于提高代码的安全性;而指针操作容易导致内存泄漏、野指针等问题。
    总之,迭代器是一种比指针更高级、更安全的抽象工具,可以方便地操作各种容器中的元素,具有更好的兼容性和可扩展性。

迭代器分类

根据迭代器所支持的操作和功能,C++迭代器可分为五类:

a. 输入迭代器(Input Iterator)

输入迭代器是一种只读迭代器,主要用于访问容器中的元素。它支持以下操作:

  1. 递增(++)
  2. 间接访问(*):仅限于读取,不能用于修改元素
  3. 比较(== 和 !=)
    输入迭代器通常用于单遍扫描的算法,如find、count等.

b. 输出迭代器(Output Iterator)

输出迭代器是一种只写迭代器,主要用于向容器中插入或修改元素。它支持以下操作:

  1. 递增(++)
  2. 间接访问(*):仅限于写入,不能用于读取元素
    输出迭代器通常用于单遍扫描的算法,如copy、transform等。

c. 前向迭代器(Forward Iterator)

前向迭代器同时具备输入迭代器和输出迭代器的功能,可以进行读写操作。它支持以下操作:

  1. 递增(++)
  2. 间接访问(*):可用于读取和修改元素
  3. 比较(== 和 !=)
    前向迭代器通常用于支持多遍扫描的算法,如replace、remove_if等。

d. 双向迭代器(Bidirectional Iterator)

双向迭代器在前向迭代器的基础上增加了递减操作,可以向前向后遍历容器。它支持以下操作:

  1. 递增(++)
  2. 递减(–)
  3. 间接访问(*):可用于读取和修改元素
  4. 比较(== 和 !=)
    双向迭代器通常用于支持反向操作的算法,如reverse、find_end等。

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

随机访问迭代器具有最丰富的功能,可以实现随机访问容器中的任意元素。它支持以下操作:

  1. 递增(++)和递减(–)
  2. 间接访问(*):可用于读取和修改元素
  3. 比较(==、!=、<、>、<= 和 >=)
  4. 加法和减法操作(+、-、+= 和 -=)
  5. 下标操作([])
    随机访问迭代器通常用于支持快速访问容器中任意位置元素的算法,如sort、binary_search等。此类迭代器可以直接跳跃到容器中的任意位置,具有更高的遍历性能。

五类迭代器在C++标准库中的典型应用

  • 输入迭代器:std::istream_iterator、std::istreambuf_iterator
  • 输出迭代器:std::ostream_iterator、std::ostreambuf_iterator、std::back_insert_iterator、-std::front_insert_iterator、std::insert_iterator
  • 前向迭代器:std::forward_list、std::unordered_set、std::unordered_map、std::unordered_multiset、std::unordered_multimap中的迭代器
  • 双向迭代器:std::list、std::set、std::map、std::multiset、std::multimap中的迭代器
  • 随机访问迭代器:std::vector、std::deque、std::array、std::string中的迭代器

STL中的迭代器

a. 容器和迭代器的关系

在STL中,容器和迭代器有着紧密的联系。容器负责存储和组织数据,而迭代器则提供了访问和操作容器中元素的统一接口。迭代器可以被视为容器的一个轻量级“视图”,它可以在不改变容器结构的情况下实现对元素的访问和修改。此外,迭代器还有助于将容器与算法解耦,使得算法可以更加通用地应用于不同类型的容器。

b. 各种容器的迭代器类型

STL中的容器大致可以分为三类:顺序容器、关联容器和无序关联容器。它们分别对应不同的迭代器类型:

i. 顺序容器(vector、list、deque)

顺序容器中的元素按照线性顺序存储,因此它们的迭代器通常具有随机访问(vector和deque)或双向访问(list)的功能。

  • vector和deque的迭代器类型:随机访问迭代器(Random Access Iterator)
  • list的迭代器类型:双向迭代器(Bidirectional Iterator)

ii. 关联容器(set、map、multiset、multimap)

关联容器中的元素按照一定的顺序或者规则存储,如按键值排序或者基于哈希值的存储。因此,它们的迭代器通常具有双向访问的功能。

  • set、map、multiset、multimap的迭代器类型:双向迭代器(Bidirectional Iterator)

iii. 无序关联容器(unordered_set、unordered_map、unordered_multiset、unordered_multimap)

无序关联容器中的元素基于哈希表实现存储,元素的存储顺序并不固定。因此,它们的迭代器通常具有前向访问的功能。

  • unordered_set、unordered_map、unordered_multiset、unordered_multimap的迭代器类型:前向迭代器(Forward Iterator)

了解STL中各种容器的迭代器类型有助于我们根据实际需求选择合适的容器和迭代器,从而提高编程效率和程序性能。同时,了解容器和迭代器之间的关系可以帮助我们更好地利用STL库提供的功能,编写更加高效和灵活的代码。


常用的迭代器操作和STL算法的应用实例

1. 迭代器操作

以下是一些常见的迭代器操作:

递增(++)和递减(–):用于将迭代器移动到容器中的下一个或上一个元素。
间接访问(*):用于获取或修改迭代器所指向的元素的值。
加法和减法操作(+、-、+= 和 -=):仅适用于随机访问迭代器,用于在容器中跳跃式地移动迭代器。
下标操作([]):仅适用于随机访问迭代器,用于直接访问容器中指定位置的元素。

2. STL算法实例

以下是一些使用迭代器的STL算法实例:

a. find(查找)

#include <algorithm>
#include <vector>
#include <iostream>int main() {std::vector<int> vec{3, 1, 4, 1, 5, 9, 2, 6};int target = 5;auto it = std::find(vec.begin(), vec.end(), target);if (it != vec.end()) {std::cout << "Found " << target << " at position: " << std::distance(vec.begin(), it) << std::endl;} else {std::cout << "Not found" << std::endl;}return 0;
}

b. sort(排序)

#include <algorithm>
#include <vector>
#include <iostream>int main() {std::vector<int> vec{3, 1, 4, 1, 5, 9, 2, 6};std::sort(vec.begin(), vec.end());for (const auto &val : vec) {std::cout << val << " ";}std::cout << std::endl;return 0;
}

c. count(计数)

#include <algorithm>
#include <vector>
#include <iostream>int main() {std::vector<int> vec{3, 1, 4, 1, 5, 9, 2, 6};int target = 1;int count = std::count(vec.begin(), vec.end(), target);std::cout << "Number of " << target << "s: " << count << std::endl;return 0;
}

迭代器操作

在本节中,我们将介绍迭代器的一些基本操作,这些操作有助于我们更好地使用迭代器来操作容器中的元素。

a. 常用操作

//迭代器常用运算操作
*iter                //对iter进行解引用,返回迭代器iter指向的元素的引用
iter->men            //对iter进行解引用,获取指定元素中名为men的成员。等效于(*iter).men
++iter                //给iter加1,使其指向容器的下一个元素
iter++
--iter                //给iter减1,使其指向容器的前一个元素
iter--
iter1==iter2        //比较两个迭代器是否相等,当它们指向同一个容器的同一个元素或者都指向同同一个容器的超出末端的下一个位置时,它们相等 
iter1!=iter2
//使用迭代器遍历容器,并把每个元素置0
for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();++iter)*iter=0;//初始化mid迭代器,使其指向v中最靠近正中间的元素
vector<int>::iterator    mid=v.begin()+v.size()/2;   

在C++定义的容器类型中,只有vector和queue容器提供迭代器算数运算和除!=和==之外的关系运算:

iter+n     //在迭代器上加(减)整数n,将产生指向容器中钱前面(后面)第n个元素的迭代器。新计算出来的迭代器必须指向容器中的元素或超出容器末端的下一个元素
iter-niter1+=iter2        //将iter1加上或减去iter2的运算结果赋给iter1。两个迭代器必须指向容器中的元素或超出容器末端的下一个元素
iter1-=iter2iter1-iter2      //两个迭代器的减法,得出两个迭代器的距离。两个迭代器必须指向容器中的元素或超出容器末端的下一个元素>,>=,<,<=        //元素靠后的迭代器大于靠前的迭代器。两个迭代器必须指向容器中的元素或超出容器末端的下一个元素
  • 迭代器const_iterator

每种容器还定义了一种名为const_iterator的类型。

该类型的迭代器只能读取容器中的元素,不能用于改变其值。

之前的例子中,,而const_iterator类型的迭代器只能用于读不能进行重写。

for(vector<int>::const_iterator iter=ivec.begin();iter!=ivec.end();++iter)cout<<*iter<<endl;       //合法,读取容器中元素值for(vector<int>::const_iterator iter=ivec.begin();iter!=ivec.end();++iter)*iter=0;        //不合法,不能进行写操作
  • cbegin和cend运算符

**cbegincend 运算符无论对象本身是否是常量,返回值都是const_iterator.

  • 注意

const_iterator和const iterator是不一样的,

后者对迭代器进行声明时,必须对迭代器进行初始化,并且一旦初始化后就不能修改其值。

这有点像常量指针和指针常量的关系。

vector<int>    ivec(10);
const    vector<int>::iterator    iter=ivec.begin();
*iter=0;    //合法,可以改变其指向的元素的值
++iter;    //不合法,无法改变其指向的位置

b. 增加和减少迭代器

迭代器可以通过递增和递减操作来移动到容器中的其他元素。对于双向迭代器和随机访问迭代器,可以使用++和–操作符。对于随机访问迭代器,还可以使用+=和-=操作符来实现跳跃式的移动。

std::vector<int> vec{1, 2, 3, 4, 5};
auto it = vec.begin();++it; // it现在指向元素2
--it; // it现在指向元素1
it += 2; // it现在指向元素3
it -= 1; // it现在指向元素2

c. 读取和修改元素值

使用迭代器可以方便地读取和修改容器中的元素。通过对迭代器进行解引用操作,我们可以获得迭代器所指向的元素的引用。

std::vector<int> vec{1, 2, 3, 4, 5};
auto it = vec.begin();int val = *it; // 读取元素值,此时val为1
*it = 10; // 修改元素值,此时vec为{10, 2, 3, 4, 5}

d. 迭代器间的关系比较

迭代器之间可以进行关系比较,如等于、不等于、小于、小于等于、大于和大于等于等。这些比较操作对于判断迭代器是否到达某个位置或者在某个范围内非常有用。

std::vector<int> vec{1, 2, 3, 4, 5};
auto it1 = vec.begin();
auto it2 = vec.end();if (it1 != it2) {std::cout << "it1 and it2 are not equal" << std::endl;
}

e. 迭代器适配器(如反向迭代器、插入迭代器等)

迭代器适配器是一种特殊的迭代器,它可以在原有迭代器的基础上提供额外的功能。

反向迭代器

反向迭代器允许我们从后向前遍历容器。使用rbegin()和rend()函数可以获得容器的反向迭代器。

std::vector<int> vec{1, 2, 3, 4, 5};
for (auto it = vec.rbegin(); it != vec.rend(); ++it) {std::cout << *it << " ";
}
std::cout << std::endl;

插入迭代器

插入迭代器允许我们在不改变原有容器迭代器的情况下,向容器中插入新元素。C++标准库提供了三种插入迭代器:back_inserter、front_inserter和inserter。

std::vector<int> vec1{1, 2, 3};
std::vector<int> vec2{4, 5, 6};// 使用back_inserter将vec2的元素追加到vec1的末尾
std::copy(vec2.begin(), vec2.end(), std::back_inserter(vec1));
// vec1现在为{1, 2, 3, 4, 5, 6}std::deque<int> deq1{1, 2, 3};
std::deque<int> deq2{4, 5, 6};// 使用front_inserter将deq2的元素插入到deq1的前面
std::copy(deq2.begin(), deq2.end(), std::front_inserter(deq1));
// deq1现在为{6, 5, 4, 1, 2, 3}std::list<int> list1{1, 2, 3, 6, 7, 8};
std::list<int> list2{4, 5};// 使用inserter将list2的元素插入到list1的指定位置(在3和6之间)
std::copy(list2.begin(), list2.end(), std::inserter(list1, std::next(list1.begin(), 3)));
// list1现在为{1, 2, 3, 4, 5, 6, 7, 8}

迭代器失效问题

迭代器失效是在编写C++代码时常常需要注意的问题,尤其是在操作容器时。以下是迭代器失效的相关概念、原因和避免方法。

a. 什么是迭代器失效

迭代器失效是指一个原本指向容器中某个元素的迭代器,在容器发生某些操作后,不再有效地指向原先的元素或者无法完成预期的操作。这种情况可能导致程序的行为变得不可预测,甚至引发程序崩溃。

b. 迭代器失效的原因

迭代器失效的原因主要与容器的结构和操作有关。以下是一些常见的迭代器失效原因:

  • 容器的内存重新分配:当向容器中添加元素时,如vector、deque等,如果超过容器当前的容量,容器可能会重新分配内存空间,导致原有的迭代器失效。
  • 元素的删除:从容器中删除元素,如erase()等操作,可能导致指向被删除元素的迭代器失效。此外,在某些容器(如list)中,删除操作可能还会影响指向其他元素的迭代器。
  • 元素的插入:向容器中插入元素,如insert()等操作,可能导致指向插入位置之后的元素的迭代器失效。

c. 如何避免迭代器失效

以下是一些避免迭代器失效的策略:

  • 尽量使用支持自动更新的容器:在某些容器(如list)中,元素的插入和删除操作不会影响其他元素的迭代器。在可能出现迭代器失效问题的场景中,使用这类容器可以降低风险。
  • 避免在遍历过程中修改容器结构:在使用迭代器遍历容器时,避免同时进行插入或删除操作。如果需要修改容器结构,可以先收集需要修改的元素,然后在遍历结束后进行统一的操作。
  • 使用返回的迭代器:对于可能导致迭代器失效的操作,如erase()等,通常会返回一个有效的迭代器。在操作后,可以使用返回的迭代器更新失效的迭代器,以保持迭代器的有效性。
  • 预留足够的空间:在可能导致内存重新分配的容器(如vector)中,可以预先使用reserve()函数为容器预留足够的空间,以减少内存重新分配的风险。

C++11及以后版本中的新特性

C++11及以后版本中的新特性为迭代器带来了许多便利,使得我们在操作容器时能够更加简洁和高效。以下是这些新特性的简介及其在迭代器中的应用。

a. 范围for循环

范围for循环是C++11引入的一种新的循环结构,它允许我们直接遍历容器中的元素,而无需显式创建迭代器。范围for循环的语法如下:

for (declaration : range) {// loop body
}

以下是一个使用范围for循环遍历容器的示例:

#include <vector>
#include <iostream>int main() {std::vector<int> vec{1, 2, 3, 4, 5};for (const auto &val : vec) {std::cout << val << " ";}std::cout << std::endl;return 0;
}

b. auto关键字在迭代器中的应用

C++11引入了auto关键字,它可以让编译器根据初始化表达式自动推导出变量的类型。在迭代器中,我们可以利用auto关键字简化迭代器的声明和初始化。以下是一个使用auto关键字的示例:

#include <vector>
#include <iostream>int main() {std::vector<int> vec{1, 2, 3, 4, 5};for (auto it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;return 0;
}

c. 基于范围的迭代器适配器

C++14及以后的版本引入了一些基于范围的迭代器适配器,如std::begin()、std::end()、std::cbegin()和std::cend()等,它们可以作用于任何具有.begin()和.end()成员函数的类型,为我们提供了一种统一的访问方式。以下是一个使用基于范围的迭代器适配器的示例:

#include <vector>
#include <iostream>
#include <iterator>int main() {std::vector<int> vec{1, 2, 3, 4, 5};for (auto it = std::begin(vec); it != std::end(vec); ++it) {std::cout << *it << " ";}std::cout << std::endl;return 0;
}

通过使用C++11及以后版本中的新特性,我们可以编写更加简洁、易读和高效的代码。在实际编程中,熟练运用这些新特性将有助于提高我们的编程能力和代码质量。


实际应用举例

迭代器在实际编程中有很多应用,以下是一些常见的迭代器应用示例。

a. 使用迭代器实现常见算法

i. 查找

#include <vector>
#include <iostream>
#include <algorithm>int main() {std::vector<int> vec{1, 2, 3, 4, 5};int target = 3;auto it = std::find(vec.begin(), vec.end(), target);if (it != vec.end()) {std::cout << "Found " << target << " at position: " << std::distance(vec.begin(), it) << std::endl;} else {std::cout << "Not found" << std::endl;}return 0;
}

ii. 排序

#include <vector>
#include <iostream>
#include <algorithm>int main() {std::vector<int> vec{5, 3, 1, 4, 2};std::sort(vec.begin(), vec.end());for (const auto &val : vec) {std::cout << val << " ";}std::cout << std::endl;return 0;
}

iii. 复制

#include <vector>
#include <iostream>
#include <algorithm>int main() {std::vector<int> src{1, 2, 3, 4, 5};std::vector<int> dest(src.size());std::copy(src.begin(), src.end(), dest.begin());for (const auto &val : dest) {std::cout << val << " ";}std::cout << std::endl;return 0;
}

iv. 删除

#include <vector>
#include <iostream>
#include <algorithm>int main() {std::vector<int> vec{1, 2, 3, 4, 5};int target = 3;auto it = std::remove(vec.begin(), vec.end(), target);vec.erase(it, vec.end());for (const auto &val : vec) {std::cout << val << " ";}std::cout << std::endl;return 0;
}

b. 迭代器在自定义数据结构中的应用

当我们需要为自定义数据结构提供迭代器支持时,可以通过实现相应的迭代器类来完成。以下是一个简单的自定义链表类及其迭代器的示例:

#include <iostream>template <typename T>
class LinkedList {
public:struct Node {T data;Node *next;};class Iterator {public:Iterator(Node *ptr) : current(ptr) {}bool operator!=(const Iterator &other) const { return current != other.current; }T &operator*() { return current->data; }Iterator &operator++() {current = current->next;return *this;}private:Node *current;};LinkedList() : head(nullptr), tail(nullptr) {}~LinkedList() { clear(); }void push_back(const T &value) {Node *newNode = new Node{value, nullptr};if (tail) {tail->next = newNode;tail = newNode;} else {head = tail = newNode;
}Iterator begin() { return Iterator(head); }
Iterator end() { return Iterator(nullptr); }void clear() {Node *current = head;while (current) {Node *next = current->next;delete current;current = next;}head = tail = nullptr;
}
private:
Node *head;
Node *tail;
};int main() {
LinkedList<int> list;
list.push_back(1);
list.push_back(2);
list.push_back(3);
list.push_back(4);
list.push_back(5);       
for (int val : list) {std::cout << val << " ";
}
std::cout << std::endl;list.clear();return 0;
}

在这个示例中,我们实现了一个简单的链表类LinkedList,并为其提供了迭代器支持。LinkedList::Iterator类实现了常用的迭代器操作,如operator!=()operator*()operator++()等。通过这些操作,我们可以方便地使用范围for循环遍历自定义链表。


实际应用中,迭代器可以帮助我们编写更加通用、高效和易于维护的代码。熟练掌握迭代器的使用方法对于提高编程能力和代码质量具有重要意义。


总结

在本文中,我们详细讨论了C++迭代器的相关概念和应用。

a. 回顾本文讨论的主要内容

我们首先介绍了迭代器的定义和初始化,以及与指针的区别。
然后,我们详细讨论了迭代器的分类,包括输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器。
接着,我们探讨了STL中各种容器的迭代器类型,包括顺序容器、关联容器和无序关联容器。
此外,我们还讨论了C++11及以后版本中迭代器的新特性,如范围for循环、auto关键字和基于范围的迭代器适配器。
我们还介绍了迭代器失效的问题,包括失效的原因和如何避免失效。
最后,我们提供了一些迭代器在实际应用中的示例,包括常见算法和自定义数据结构中的应用。

b. C++迭代器在编程中的重要性

C++迭代器在编程中具有重要意义。迭代器为我们提供了一种通用、高效且抽象的方式来访问和操作容器中的元素。通过掌握迭代器的使用,我们可以更好地理解C++容器和算法的工作原理,提高编程能力和代码质量。

c. 鼓励读者深入学习和实践

我们鼓励读者深入学习和实践迭代器的相关知识。在实际编程过程中,可以尝试为自定义数据结构实现迭代器,或者使用迭代器编写一些通用的算法。通过不断的实践,你将更加熟练地运用迭代器,从而编写出更加优雅、高效的代码。

相关文章:

深入理解C++迭代器:让你的C++代码更加灵活

C迭代器&#xff1a;更加优雅的容器操作方式引言C迭代器简介a. 迭代器的定义b. 迭代器的作用c. 迭代器与指针的区别迭代器分类a. 输入迭代器&#xff08;Input Iterator&#xff09;b. 输出迭代器&#xff08;Output Iterator&#xff09;c. 前向迭代器&#xff08;Forward Ite…...

Java 读取Excel模板中的数据到实体类

目录一. 前提条件1.1 需求1.2 分析二. 准备2.1 自定义注解2.2 封装Excel的实体类三. 前台四. Controller层五. Service层&#x1f4aa;&#x1f4aa;&#x1f4aa;六. 效果一. 前提条件 1.1 需求 从指定的Excel模板中读取数据&#xff0c;将读取到的数据存储到数据库中。 1.2…...

【java基础】Socket网络编程

文章目录说明InetAddress介绍Socket介绍ServerSocket介绍实现简单的Socket通信总结说明 这里介绍下如何在java里面进行socket编程 InetAddress介绍 这个类表示一个Internet协议(IP)地址&#xff0c;我们可以通过ip或者主机名来构建这个类 Testpublic void t1() throws Except…...

转发和重定向区别

转发和重定向 1.0 面试提问 定义不同跳转的方式不同数据共享不同最终的URL地址不同代码实现不同 1. 转发 1.1 概念 转发实际上在服务器端进行页面的跳转操作&#xff0c;请求转发&#xff1a;一种在服务器内部的资源的跳转的方式。 访问A&#xff0c;A请求转发了B&#xff0c…...

java面试题(持续更新)

java面试题&#xff08;持续更新&#xff09; java 基础 java面向对象有哪些特征 面向对象的三大特征&#xff1a;封装、继承、多态 封装&#xff1a;隐藏了类的内部实现机制&#xff0c;可以在不影响使用的情况下改变类的内部结构&#xff0c;同时也保护了数据&#xff0c;…...

【花雕学AI】09:发挥ChatGPT最大潜力——产生高质量内容的九种方法和建议

人工智能&#xff08;AI&#xff09;是当今科技领域最热门和最有前景的话题之一&#xff0c;它已经渗透到了我们生活和工作的方方面面&#xff0c;给我们带来了许多便利和惊喜。而在AI的众多分支中&#xff0c;自然语言处理&#xff08;NLP&#xff09;是最贴近人类的一个领域&…...

实战打靶集锦-013-Loly

**写在前面&#xff1a;**记录博主的一次打靶经历 目录1. 主机发现2. 端口扫描3. 服务枚举4. web服务探查4.1 WordPress探测4.2 使用metasploit4.3 使用wpscan4.4 阶段性回顾5. 提权5.1 弱密码提权5.2 操作系统信息枚举5.3 定时任务枚举5.4 passwd信息枚举5.5 可执行文件枚举5.…...

程序员OKR学习法

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl OKR管理法 OKR&#xff08;Objectives and Key Results&#xff09;管理法是一种目标管理方法&#xff0c;旨在通过制定明确的目标和可量化的关键结果来帮助组织、团队和个人…...

【从零开始学习 UVM】6.6、UVM 激励产生 —— UVM Virtual Sequence【重要】

文章目录 使用virtual sequencer不使用virtual sequencervirtual sequence是一个容器,用于在环境中的virtual sequencer上启动多个sequence。 这个virtual sequence通常由一个具有对真实sequencers句柄的virtual sequencers执行。 需要virtual sequence的原因是当您需要在不…...

蓝桥杯:阶乘约数

蓝桥杯&#xff1a;阶乘约数https://www.lanqiao.cn/problems/1020/learning/ 目录 题目描述 填空题&#xff1a;答案是 39001250856960000 题目分析 AC代码(Java) 暴力 线性筛 题目描述 填空题 定义阶乘 n!123⋅⋅⋅n。 请问 100! &#xff08;100 的阶乘&#xff09;有…...

最大数字

[蓝桥杯 2022 国 B] 最大数字 题目描述 给定一个正整数 NNN。你可以对 NNN 的任意一位数字执行任意次以下 2 种操作: 将该位数字加 111。如果该位数字已经是 999&#xff0c;加 111 之后变成 000。 将该位数字减 111。如果该位数字已经是 000&#xff0c;减 111 之后变成 99…...

【java进阶08:异常】finally关键字、自定义异常类、用户业务作业、军队武器作业

java中的异常处理机制 异常在java中以类和对象的形式存在&#xff0c;那么异常的继承结构是怎样的&#xff1f;我们可以使用UML图来描述以下继承结构 画UML图的工具&#xff1a;Rational Rose、starUML等 Object下有Throwable&#xff08;可抛出的&#xff09; Throwable下有两…...

#课程笔记# 电路与电子技术基础 课堂笔记 第6章 半导体器件的基本特性

6.1 半导体基础知识 6.1.1 本征半导体 完全纯净的、结构完整的半导体称为本征半导体。 常用的半导体材料有硅和锗&#xff0c;它们都是四价元素&#xff0c;原子最外层轨道有四个价电子。 若将纯净的半导体制成晶体&#xff0c;则原子形成排列整齐的点阵。 点阵是由共价键提供…...

skimage.filters.apply_hysteresis_threshold详解

本文内容均参考scipy1.9.1scipy1.9.1scipy1.9.1版本的源码&#xff0c;若有任何不当欢迎指出 我们截取官方注释如下&#xff1a; def apply_hysteresis_threshold(image, low, high):"""Apply hysteresis thresholding to image.This algorithm finds regions …...

一、基础算法5:前缀和与差分 模板题+算法模板(前缀和,子矩阵的和,差分,差分矩阵)

文章目录算法模板前缀和模板子矩阵的和模板差分模板差分矩阵模板模板题前缀和原题链接题目题解子矩阵的和原题链接题目题解差分原题链接题目题解差分矩阵原题链接题目题解算法模板 前缀和模板 S[i] a[1] a[2] ... a[i] a[l] ... a[r] S[r] - S[l - 1]子矩阵的和模板 S[i…...

Python矩阵分解之QR分解

文章目录QR和RQ分解其他函数QR和RQ分解 记AAA为方阵&#xff0c;P,QP, QP,Q分别为正交单位阵和上三角阵&#xff0c;则形如AQRAQRAQR的分解为QR分解&#xff1b;形如ARQARQARQ的分解为RQ分解。 在scipy.linalg中&#xff0c;为二者提供了相同的参数&#xff0c;除了待分解矩阵…...

随机森林程序

n_estimators:数值型取值 含义&#xff1a;森林中决策树的个数&#xff0c;默认是10 criterion:字符型取值 含义&#xff1a;采用何种方法度量分裂质量&#xff0c;信息熵或者基尼指数&#xff0c;默认是基尼指数 max_features:取值为int型, float型, string类型…...

每日一练2627——变态跳台阶快到碗里来不用加减乘除做加法三角形

文章目录变态跳台阶思路&#xff1a;代码&#xff1a;快到碗里来思路&#xff1a;代码&#xff1a;不用加减乘除做加法思路&#xff1a;代码&#xff1a;三角形思路&#xff1a;代码&#xff1a;变态跳台阶 题目链接&#xff1a; 思路&#xff1a; 这个题目很容易理解&#…...

LeetCode-146. LRU 缓存

目录LRU理论题目思路代码实现一代码实现二题目来源 146. LRU 缓存 LRU理论 LRU 是 Least Recently Used 的缩写&#xff0c;这种算法认为最近使用的数据是热门数据&#xff0c;下一次很大概率将会再次被使用。而最近很少被使用的数据&#xff0c;很大概率下一次不再用到。当缓…...

#课程笔记# 电路与电子技术基础 课堂笔记 第3章 电路分析的几个定理

3.1 叠加定理 激励&#xff1a;电流源或电压源 响应&#xff1a;电流或电压 叠加定理一般用于已知激励或响应中的一种&#xff0c;求另一种。做法就是&#xff0c;每次只求一个激励作用下的响应&#xff0c;将其他激励置零&#xff0c;置零的具体做法是&#xff0c;电压源变…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...