1、迭代器(iterators)概念
(1)迭代器是一种抽象的设计概念,其定义为:提供一种方法,使他能够按顺序遍历某个聚合体(容器)所包含的所有元素,但又不需要暴露该容器的内部表现方式。

(2)迭代器是一种行为类似智能指针的对象, 而指针最常见的行为就是内 容提领和成员 访问。 因此迭代器最重要的行为就是对operator*和operator->进行重载。

(3)STL的中心思想在于: 将数据容器和算法分开, 彼此独立设计, 最后再以一贴胶合剂( iterator) 将它们撮合在一起。STL的迭代器是一个可遍历STL容器全部或者部分数据。

2、迭代器的使用

以list和vector为例说明

 #include<iostream>
#include<vector>
#include<list>
#include<algorithm>
#include<string>
using namespace std;
void Test1()
{
vector<int>v1;
v1. push_back() ;
v1. push_back() ;
v1. push_back() ;
v1. push_back() ;
v1. push_back() ;
//迭代器遍历顺序表
vector<int>: : iteratorit=v1. begin() ;
for(; it! =v1. end() ; ++it)
{
cout<<*it<<" ";
}
cout<<endl;
// STL的排序算法
sort(v1. begin() , v1. end() ) ;
it=v1. begin() ;
for(; it! =v1. end() ; ++it)
{
cout<<*it<<" ";
}
cout<<endl;
}
voidTest2()
{
list<string>l1;
l1. push_back("xjh") ;
l1. push_back("zpw") ;
l1. push_back("yb") ;
l1. push_back("whb") ;
//迭代器遍历链表
list<string>: : iteratorit=l1. begin() ;
for(; it! =l1. end() ; ++it)
{
cout<<*it<<" ";
}
cout<<endl;
// STL的替换算法
replace(l1. begin() , l1. end() , "xjh", "lcf") ;
it=l1. begin() ;
for(; it! =l1. end() ; ++it)
{
cout<<*it<<" ";
}
cout<<endl;
}
voidTest3()
{
list<string>l1;
l1. push_back("xjh") ;
l1. push_back("zpw") ;
l1. push_back("yb") ;
l1. push_back("whb") ;
//迭代器遍历链表
list<string>: : iteratorit=l1. begin() ;
for(; it! =l1. end() ; ++it)
{
cout<<*it<<" ";
}
cout<<endl;
// STL的find算法查找迭代器区间的数据, 并返回找到节点的迭代器
it=find(l1. begin() , l1. end() , "yb") ;
if(it! =l1. end() )
{
cout<<"find success: "<<*it<<endl;
//通过迭代器修改节点数据
*it="yls";
}
it=find(l1. begin() , l1. end() , "yb") ;
if(it==l1. end() )
{
cout<<"find failed"<<endl;
}
}

3、什么是迭代器失效
以vector为例,当我们插入一个元素时它的预分配空间不够时,它会重新申请一段新空间,将原空间上的元素 复制到新的空间上去,然后再把新加入的元素放到新空间的尾部,以满足vector元素要求连续存储的目的。而后原空间会被系统撤销或征做他用,于是指向原 空间的迭代器就成了类似于“悬垂指针”一样的东西,指向了一片非法区域。如果使用了这样的迭代器会导致严重的运行时错误就变得很自然了。这也是许多书上叙 述vector在insert操作后“可能导致所有迭代器实效”的原因。但是想到这里我不禁想到vector的erase操作的叙述是“会导致指向删除元 素和删除元素之后的迭代器失效”。

 void PrintVector(vector<int>&v)
{
vector<int>: : iteratorit=v. begin() ;
for(; it! =v. end() ; ++it)
{
cout<<*it<<" ";
}
cout<<endl;
}
void Test1()
{
vector<int>v1;
v1. push_back() ;
v1. push_back() ;
v1. push_back() ;
v1. push_back() ;
v1. push_back() ;
v1. push_back() ;
v1. push_back() ;
v1. push_back() ;
PrintVector(v1) ;
//迭代器失效
vector<int>: : iteratorit=v1. begin() ;
while(it! =v1. end() )
{
if(*it% == )
it=v1. erase(it) ;
else
++it;
}
PrintVector(v1) ;
}
void PrintList(list<int>&l1)
{
list<int>: : iteratorit=l1. begin() ;
for(; it! =l1. end() ; ++it)
{
cout<<*it<<" ";
}
cout<<endl;
}
void Test2()
{
list<int>l1;
l1. push_back() ;
l1. push_back() ;
l1. push_back() ;
l1. push_back() ;
l1. push_back() ;
l1. push_back() ;
l1. push_back() ;
l1. push_back() ;
PrintList(l1) ;
//迭代器失效
list<int>: : iteratorit=l1. begin() ;
while(it! =l1. end() )
{
if(*it% == )
it=l1. erase(it) ;
else
++it;
}
PrintList(l1) ;
}
 // 1.正向迭代器/反向迭代器
// 2.const/非const
void PrintList(const list<int>& l)
{
list<int>::const_iterator it = l.begin();
while (it != l.end())
{
cout<<*it<<" ";
++it;
}
cout<<endl; list<int>::const_reverse_iterator rit = l.rbegin();
while (rit != l.rend())
{
//*rit = 10;
cout<<*rit<<" ";
++rit;
}
cout<<endl; //list<int>::iterator it1 = l.end();
//while (it1 != l.begin())
//{
// --it1;
// cout<<*it1<<" ";
//}
//cout<<endl;
}

归纳一下迭代器失效的类型:

(1)由于容器元素整体“迁移”导致存放原容器元素的空间不再有效,从而使得指向原空间的迭代器失效。

(2)由于删除元素使得某些元素次序发生变化使得原本指向某元素的迭代器不再指向希望指向的元素。

4、模拟实现简化版List迭代器&嵌入List

 #pragma once
#include<iostream>
#include<assert.h>
using namespace std; template <class T>
struct ItListNode
{
ItListNode<T>* _prev; // 指向前一个结点的指针
ItListNode<T>* _next; // 指向后一个结点的指针
T data; // 结点数据
ItListNode(const T& n)
:_prev(NULL)
,_next(NULL)
,data(n)
{}
};
// List的迭代器
template <class T, class Ref, class Ptr>
class ListIterator
{
public:
typedef ItListNode<T> Node;
Node* node; // 指向节点的指针
// 这里Ref、 Ptr模板参数主要是为了方便复用的方式实现const类型的迭代器ConstIterator
typedef ListIterator<T, Ref, Ptr> Self; ListIterator(Node* n)
:node(n)
{}
Ref operator*() {
return node->data;
}
Ptr operator->() {
return &node->data;
//return &(operator*());
}
Self& operator--() {
node = node->_prev;
return *this;
}
Self& operator--(int) {
Self tmp(*this);
node = node->_prev;
return tmp;
}
Self& operator++() {
node = node->_next;
return *this;
}
Self& operator++(int) {
Self tmp(*this);
node = node->_next;
return tmp;
}
bool operator != (const Self& s)const {
return node != s.node;
}
}; //双向循环链表
template <class T>
class List
{
typedef ItListNode<T> Node;
public: // 定义迭代器、 const迭代器
typedef ListIterator<T, T&, T*> Iterator;
typedef ListIterator<T, const T&, const T*> ConIterator;
List() {
Head = BuyNode(T());
Head->_prev = Head;
Head->_next = Head;
}
List(const T& l)
:Head(BuyNode(T()))
{
Head->_next = Head;
Head->_prev = Head;
ConIterator it = l.Begin();
while (it != l.End()) {
this->PushBack(*it);
++it;
}
}
List<T>& operator=(const T& l) {
if (*this != &l) {
swap(node, l.node);
}
return *this;
}
~List() {
Clear();
delete Head;
Head = NULL;
}
Iterator Begin() {
return Iterator(Head->_next);
}
ConIterator Begin()const {
return ConIterator(Head->_next);
}
Iterator End() {
return Iterator(Head);
}
ConIterator End()const {
return ConIterator(Head);
}
void Clear() {
Node*cur = Head->_next;
while (cur != Head) {
Node* next = cur->_next;
delete cur;
cur = next;
}
Head->_next = Head;
Head->_prev = Head;
}
void PushBack(const T& n) {
/*Node* tail = Head->_prev;
Node* tmp = BuyNode(n);
tail->_next = tmp;
tmp->_prev = tail;
tmp->_next = Head;
Head->_prev = tmp;*/
Insert(End(), n);
}
void PopBack() {
Erase(--End());
}
void PushFront(const T& n) {
Insert(Begin(), n);
}
void PopFront() {
Erase(Begin());
}
// 在pos前插入一个节点
void Insert(Iterator pos, const T& n) {
Node* Next = pos.node;
Node* Prev = Next->_prev;
Node* Cur = BuyNode(n);
Prev->_next = Cur;
Cur->_prev = Prev;
Cur->_next = Next;
Next->_prev = Cur;
}
// 在pos前插入一个节点
Iterator Erase(Iterator pos) {
assert(pos.node&&pos.node != Head);
Node* Cur = pos.node;
Node* Prev = Cur -> _prev;
Node* Next = Cur -> _next;
delete Cur;
Prev->_next = Next;
Next->_prev = Prev;
return Iterator(Next);
}
Iterator Find(const T& n) {
Iteraptor* it = Begin();
while (it != End()) {
if (*it == n)
return it;
}
return End();
} protected:
Node* BuyNode(const T& n) {
return new Node(n);
} private:
Node* Head;
}; // 1.测试List迭代器Iterator
void PrintList1(List<int>& l1)
{
List<int>::Iterator it = l1.Begin();
for (; it != l1.End(); ++it)
{
cout << *it << " ";
}
cout << endl;
}
//2.测试List迭代器ConstIterator
void PrintMyList(const List<int>& L1) {
List<int>::ConIterator it1 = L1.Begin();
while (it1 != L1.End()) {
cout << *it1 << " ";
++it1;
}
cout << endl;
}
int main() {
List<int> L1;
L1.PushBack();
L1.PushBack();
L1.PushBack();
L1.PushBack();
PrintMyList(L1); PrintList1(L1);
L1.PopBack();
PrintMyList(L1); L1.PushFront();
L1.PushFront();
L1.PushFront();
L1.PushFront();
PrintMyList(L1);
L1.PopFront();
PrintMyList(L1); getchar();
return ;
}

模拟实现简化版List迭代器&嵌入List的更多相关文章

  1. Java8 parallelStream与迭代器Iterator性能

    定义一个测试类 public class TestParallelStream { private List<Integer> list; private int size; privat ...

  2. 【ES6】迭代器与可迭代对象

    ES6 新的数组方法.集合.for-of 循环.展开运算符(...)甚至异步编程都依赖于迭代器(Iterator )实现.本文会详解 ES6 的迭代器与生成器,并进一步挖掘可迭代对象的内部原理与使用方 ...

  3. Lua 与 Redis

    Lua 与 Redis 标签: Java与NoSQL 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis - 案例-实现访问频率限制: 实现访问者 $ip 在一定的 ...

  4. 图表控件FlowChart.NET详细介绍及免费下载地址

    FlowChart.NET是一款专业的.NET平台下的流程图及图表控件,它可以运行在任何C#, VB.NET或Delphi.NET语言编写的软件中.能够帮助你创建工作流程图.对象层次和关系图.网络拓扑 ...

  5. Lua语言模型 与 Redis应用

    Lua语言模型 与 Redis应用 标签: Java与NoSQL 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis. 本篇博客主要介绍了 Lua 语言不一样的设计 ...

  6. Redis结合Lua脚本实现高并发原子性操作

    从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis … 案例-实现访问频率限制: 实现访问者 $ip 在一定的时间 $time 内只能访问 $limit 次. 非脚 ...

  7. 四大机器学习编程语言对比:R、Python、MATLAB、Octave

    本文作者是一位机器学习工程师,他比较了四种机器学习编程语言(工具):R.Python.MATLAB 和 OCTAVE.作者列出了这些语言(工具)的优缺点,希望对想开始学习它们的人有用. 图源:Pixa ...

  8. 一个基于netty的websocket聊天demo

    这里,仅仅是一个demo,模拟客户基于浏览器咨询卖家问题的场景,但是,这里的demo中,卖家不是人,是基于netty的程序(我就叫你uglyRobot吧),自动回复了客户问的问题. 项目特点如下: 1 ...

  9. NAACL 2019 字词表示学习分析

    NAACL 2019 表示学习分析 为要找出字.词.文档等实体表示学习相关的文章. word embedding 搜索关键词 word embedding Vector of Locally-Aggr ...

随机推荐

  1. 用Gradle构建Spring Boot项目

    相比起Maven的XML配置方式,Gradle提供了一套简明的DSL用于构建Java项目,使我们就像编写程序一样编写项目构建脚本.本文将从无到有创建一个用Gradle构建的Spring Boot项目, ...

  2. linux 常用命令之一

    ---恢复内容开始--- Applications->Accessories->Terminal(终端) 终端运行起来会启动一个Shell为我们服务 1.提示符是"#" ...

  3. Android5.0水波纹效果ripple实现

    1.如何设置波纹效果 // 波纹有边界 android:background="?android:attr/selectableItemBackground" // 波纹超出边界 ...

  4. Git版本切换

    前面的话 本文将以一个简单实例的形式来介绍Git版本切换 初始版本 首先,在一个自定义的位置,创建目录a,比如在D盘下 [注意]本文会用到一些常用的Linux的Shell命令,详细信息移步至此 先使用 ...

  5. huffman编码【代码】

    哈夫曼编码应该算数据结构"树"这一章最重要的一个问题了,当时大一下学期学的时候没弄懂,一年后现在算是明白了. 首先,讲讲思路. 正好这学期在学算法,这里面就用到了贪心算法,刚好练练 ...

  6. SSL证书的生成方法

    在Linux下,我们进行下面的操作前都须确认已安装OpenSSL软件包. 1.创建根证书密钥文件root.key: [root@mrlapulga:/etc/pki/CA/private]#opens ...

  7. ios url网址相关问题解说

    问题1:ios网址中存在汉字的情况,需要GB_18030_2000编码方法如下: // 汉字转编码 + (NSString *)changeChineseWithEncodingGB_18030_20 ...

  8. ABPZero中的Name和SurName处理

    使用ABPzero的朋友们都知道,User表中有Name和Surname两个字段,这两个字段对于国内的用户来说相当的不友好. 我们在尝试了很多的方法之后,发现无法完美将他们干掉. 所以尝试使用了一个比 ...

  9. ABCD多选正则表达式

    正则表达式: 4个选项,可单选可多选不允许重复 ABCD正则: regexp : /^(?!.*((A.*){2,}|(B.*){2,}|(C.*){2,}|(D.*){2,})$)[A-D]{1,4 ...

  10. 浅谈 虚方法(virtual)

    虚方法 理解:从字面意思来讲,"虚",可有可无,子类对父类的某种方法的重写,可以重写,也可以不重写. 虚方法,顾名思义(装个13),就是某种方法. 用法:public virtua ...