模拟实现简化版List迭代器&嵌入List
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的更多相关文章
- Java8 parallelStream与迭代器Iterator性能
定义一个测试类 public class TestParallelStream { private List<Integer> list; private int size; privat ...
- 【ES6】迭代器与可迭代对象
ES6 新的数组方法.集合.for-of 循环.展开运算符(...)甚至异步编程都依赖于迭代器(Iterator )实现.本文会详解 ES6 的迭代器与生成器,并进一步挖掘可迭代对象的内部原理与使用方 ...
- Lua 与 Redis
Lua 与 Redis 标签: Java与NoSQL 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis - 案例-实现访问频率限制: 实现访问者 $ip 在一定的 ...
- 图表控件FlowChart.NET详细介绍及免费下载地址
FlowChart.NET是一款专业的.NET平台下的流程图及图表控件,它可以运行在任何C#, VB.NET或Delphi.NET语言编写的软件中.能够帮助你创建工作流程图.对象层次和关系图.网络拓扑 ...
- Lua语言模型 与 Redis应用
Lua语言模型 与 Redis应用 标签: Java与NoSQL 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis. 本篇博客主要介绍了 Lua 语言不一样的设计 ...
- Redis结合Lua脚本实现高并发原子性操作
从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis … 案例-实现访问频率限制: 实现访问者 $ip 在一定的时间 $time 内只能访问 $limit 次. 非脚 ...
- 四大机器学习编程语言对比:R、Python、MATLAB、Octave
本文作者是一位机器学习工程师,他比较了四种机器学习编程语言(工具):R.Python.MATLAB 和 OCTAVE.作者列出了这些语言(工具)的优缺点,希望对想开始学习它们的人有用. 图源:Pixa ...
- 一个基于netty的websocket聊天demo
这里,仅仅是一个demo,模拟客户基于浏览器咨询卖家问题的场景,但是,这里的demo中,卖家不是人,是基于netty的程序(我就叫你uglyRobot吧),自动回复了客户问的问题. 项目特点如下: 1 ...
- NAACL 2019 字词表示学习分析
NAACL 2019 表示学习分析 为要找出字.词.文档等实体表示学习相关的文章. word embedding 搜索关键词 word embedding Vector of Locally-Aggr ...
随机推荐
- 整合第二次(SSM第一次)------------>spring+struts2+mybatis
今天我们来讲解一下SSM整合,感觉整合这个比上一篇整合更费时,原因在于自己不太熟悉MyBatis了,下午的时候恶补了一下,看了一下相关的文档和PDF电子书,知识真的是你不用就会忘记的,以后还是不能懈怠 ...
- vuex 使用文档
安装 直接下载CDN 引用 <script src="/path/to/vue.js"></script> <script src="/pa ...
- Win10《芒果TV》商店版更新v3.4.0:率先支持创意者画中画,工作娱乐两不误
在Win10创新者更新中,微软为Windows10 PC系统添加了UWP应用窗口置顶功能(亦称画中画功能),Win10版<芒果TV>更新v3.4.0,率先宣布支持画中画新特性,为广大用户带 ...
- 看Lucene源码必须知道的基本概念
终于有时间总结点Lucene,虽然是大周末的,已经感觉是对自己的奖励,毕竟只是喜欢,现在的工作中用不到的.自己看源码比较快,看英文原著的技术书也很快.都和语言有很大关系.虽然咱的技术不敢说是部门第一的 ...
- Java 9 尝鲜之JShell交互式编程环境
JShell--Java 9 的交互式编程环境 本文要求读者有基本的 Java 知识. Tips Java 9 的代码由于提供了新特性,所以有些代码并不支持向后兼容.也就是说,用 Java 9 写的代 ...
- php数组--2017-04-16
一.定义数组 (1)索引数组 $arr=array(1,2,3,3); (2)关联数组 类似于集合 $arr1=array("one"=>"111",& ...
- dev 中的GridControl中的行实现选择的功能实现
1.项目有实现不GridControl中的数据导出Excel的功能,导出的时候是把所有的数据全部导出,现在要实现可供选择的灵活的导出功能.除了全选可全不选,还可以对每一行实现选择的功能.实现起来比较简 ...
- struts1实现简单的登录功能(附源码)
环境:MyEclipse 14 ...
- Extjs6组件——Form大家族成员介绍
本文基于ext-6.0.0 一.xtype form一共有12种xtype,下面来一一举例说一下. 1.textfield 这个是用的最多的form之一. { xtype: 'textfield', ...
- 计算机程序的思维逻辑 (82) - 理解ThreadLocal
本节,我们来探讨一个特殊的概念,线程本地变量,在Java中的实现是类ThreadLocal,它是什么?有什么用?实现原理是什么?让我们接下来逐步探讨. 基本概念和用法 线程本地变量是说,每个线程都有同 ...