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. !function 笔记

    一般看JQuery插件里的写法是这样的 (function($) { //... })(jQuery); 今天看到bootstrap的javascript组件是这样写的 !function( $ ){ ...

  2. Python isinstance

    语法:isinstance(object,type) 作用:来判断一个对象是否是一个已知的类型. 其第一个参数(object)为对象,第二个参数(type)为类型名(int...)或类型名的一个列表( ...

  3. Spring Dubbo 开发笔记

    第一节:概述 Spring-Dubbo 是我自己写的一个基于spring-boot和dubbo,目的是使用Spring boot的风格来使用dubbo.(即可以了解Spring boot的启动过程又可 ...

  4. kindeditor扩展粘贴图片功能&修改图片上传路径并通过webapi上传图片到图片服务器

    前言 kindeditor是一个非常好用的富文本编辑器,它的简单使用我就不再介绍了. 而kindeditor却对图片的处理不够理想. 本篇博文需要解决的问题有两个: kindeditor扩展粘贴图片功 ...

  5. 细谈UITabBarController

    1.简述 UITabBarController和UINavigationController类似,UITabBarController也可以轻松地管理多个控制器,轻松完成控制器之间的切换,UITabB ...

  6. LinkCode 第k个排列

    http://www.lintcode.com/zh-cn/problem/permutation-sequence/# 原题 给定 n 和 k,求123..n组成的排列中的第 k 个排列. 注意事项 ...

  7. 【原创】bootstrap框架的学习 第七课 -[bootstrap表格]

    Bootstrap 表格 标签 描述 <table> 为表格添加基础样式. <thead> 表格标题行的容器元素(<tr>),用来标识表格列. <tbody& ...

  8. NodeJS 中npm包管理工具

    NPM 使用介绍 NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用. 允许用户从 ...

  9. Session攻击(会话劫持+固定)与防御

    1.简介 Session对于Web应用无疑是最重要的,也是最复杂的.对于web应用程序来说,加强安全性的第一条原则就是 – 不要信任来自客户端的数据,一定要进行数据验证以及过滤,才能在程序中使用,进而 ...

  10. Log4j appender输出类型配置

    Log4j官方的appender给出了一下几种实现 org.apache.log4j.ConsoleAppender(控制台), org.apache.log4j.FileAppender(文件), ...