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. boostrap详情解毒

    详解Bootstrap表单组件 表单常见的元素主要包括:文本输入框.下拉选择框.单选框.复选框.文本域.按钮等.下面是不同的bootstrap版本: LESS:  forms.less SASS:  ...

  2. node压力测试

    压力测试 ab测试(ApacheBench); 介绍: 这是apache提供的压测工具; 使用: 启动node服务; 我用的XAMPP,进入bin文件夹,打开命令行,执行下面命令: // -n: 总请 ...

  3. 从零开始用 Flask 搭建一个网站(一)

    前言 笔者之前未接触过 Python,只是略懂一点前端,所以说从零开始也相差无几吧.Flask 是一个轻量级的基于 Python 的框架,但是扩展性非常良好(Github 上 22000 多个 sta ...

  4. JavaScript编码解码以及C#中的编码解码

    JS: 编码 解码 escape   unescape encodeURI decodeURI encodeURIComponent decodeURIComponent C#: HttpUtilit ...

  5. BeautifulSoup库children(),descendants()方法的使用

    BeautifulSoup库children(),descendants()方法的使用 示例网站:http://www.pythonscraping.com/pages/page3.html 网站内容 ...

  6. spring 动态创建数据源

    项目需求如下,公司对外提供服务,公司本身有个主库,另外公司会为每个新客户创建一个数据库,客户的数据库地址,用户名,密码,都保存在主数据库中.由于不断有新的客户加入,所以要求,项目根据主数据库中的信息, ...

  7. border-raduis 在IE8中的兼容性问题

    border-raduis 是css3新增加的属性,我们运用起来也很方便,效果很好,但是在IE8以及之前的ie版本并不支持这个属性,怎么解决这个问题呢? 1.切成背景 这也是我经常用到的方法,虽然说有 ...

  8. PHP环境搭建之PHPstorm9+PHP5开发环境配置

    以前写过一篇zend studio+WAMP的:点这里,个人感觉写得不怎么好可是阅读数却上千了... 不过笔者身边好多人开始用PHPStrom了,所以就简单的写个教程 一.下载安装 PHPStrom下 ...

  9. IBM GPFS并行文件系统

    原文地址:http://www.hqschina.com/Show.aspx?info_lb=283&info_id=751&flag=103 IBM GPFS文件系统是一种专门为群集 ...

  10. MD5加密。

    MD5 是把文件用open打开,然后对内容hash后的值,所以和文件名无关,和位置无关,和修改时间无关,只与文件内容有关.