剖析容器List
来源:互联网 发布:淘宝福袋是死人衣服 编辑:程序博客网 时间:2024/06/09 09:20
List
零个或者多个数据元素的有限序列;
A. 是一个序列:元素之间有顺序,每一个元素都有前驱和后继;(这里的链表是一个带头节点的双向循环链表)
B. 有限的;
综上所述:ListNode的模型如下:
- 迭代器:一种遍历容器的方式,只作遍历,修改的作用,不析构节点;分为:普通迭代器(可读可改),const迭代器(可读不可改),反向迭代器(反向遍历);
- 模拟实现正向迭代器基本功能,代码如下:
template <class T>struct _ListNode{ T _data; ListNode<T>* _prev; ListNode<T>* _next; _ListNode(const T& data) :_data(data),_prev(NULL),_next(NULL) {} T& operator*() { return _data; }};template <class T, class Ref, class Ptr>struct _ListIterator{ typedef _ListNode<T> Node; typedef _ListIterator<T,Ref,Ptr> Self; Node* _node; _ListIterator(Node* node) :_node(node) {} Self& operator++()//前置++ { _node = _node->_next; return *this; } Self operator++(int)//后置++ { Self* cur(_node); _node = _node->_next; return cur; } Self& operator--()//前置-- { _node = _node->_prev; return *this; } Self operator--(int)//后置-- { Self cur(_node); _node = _node->_prev; return cur; } Ref operator*()//Ref == T& { return _node->_data; } Ptr operator->()//返回了一个指针,其实就是如何将一个迭代器转化成一个指针,使其具有指针变量的属性 { return &_node->_data;//返回了这个数的地址,将其赋给一个指针变量 } bool operator!=(const Self& t) const { return _node != t._node; }};//具有头节点的双向循环链表template <class T>class _List{ typedef _ListNode<T> Node; typedef _ListIterator<T,T&,T*> Iterator; typedef _ListIterator<T,const T&,const T*> IteratorConst;protected: Node* _head;public: Node* GetNode(const T& data)//这里表示让一个指针指向一个空间 { return new Node(data); } _List()//这是一个含有头节点的双向链表,所以头节点也应该有空间,里面的存放的数据可以设置为默认值 { _head = GetNode(T());//根据类型确定默认值 _head->_next = _head; _head->_prev = _head; } ~_List() { _clear(); /*clear_Iterator();*/ delete _head;//头节点有空间必须要析构 _head = NULL; } //普通的迭代器 Iterator Begin() { return Iterator(_head->_next); } Iterator End() { return Iterator(_head); } //const迭代器 IteratorConst Begin() const { return IteratorConst(_head->_next); } IteratorConst End() const { return IteratorConst(_head); } //没有使用迭代器以前 Node* Find(const T& data) { Node* cur = _head->_next; while(cur != _head) { if(*cur == data) return cur; cur = cur->_next; } return _head; } //使用迭代器以后 Iterator Find(const T& data) { Iterator it = Begin(); while(it != End()) { if(*it == data) return it; ++it; } return it; } //没有使用迭代器之前 void _clear() { Node* cur = _head->_next; while(cur != _head) { Node* del = cur; cur = cur->_next; delete del; } _head->_next = _head; _head->_prev = _head; } //使用迭代器以后 void clear_Iterator() { Iterator cur = Begin(); while(cur != End()) { Node* del = cur._node; ++cur; delete del; } _head->_next = _head; _head->_prev = _head; } // 设计一个双向链表,实现随机位置的插入和删除,在pos的前面进行插入 void Insert(const Node* pos,const T& data) { assert(pos); Node* cur = GetNode(data); Node* pre = pos->_prev; pre->_next = cur; cur->_prev = pre; cur->_next = pos; pos->_prev = cur; } void Insert(Iterator pos, const T& data) { assert(pos._node); Node* cur = GetNode(data); Iterator pr = --pos; pr._node->_next = cur; cur->_prev = pr._node; cur->_next = pos._node; pos._node->_prev = cur; } Iterator Erase(Iterator& pos)//删除 { assert(pos._node && pos == End());//_node不能为NULL,且不能删除_head节点 Iterator pre = --pos; Iterator nex = ++pos; pre._node->_next = nex._node; nex._node->_prev = pre._node; delete pos._node; pos = pre; return nex; } void PopFront()//头删 { Erase(Begin()); } void PopBack()//尾删 { Erase(--End()); } void PushFront(const T& data)//头插 { Insert(Begin(),data); } void PushBack(const T& data)//尾插 { Insert(End(),data); } bool IsEmpty() { return _head == _head->_next; } //模板内的成员函数也可以设计成模板函数 template <class InputIterator> //将某个对象区间内的值拷贝到当前对象中 void Assign(InputIterator first,InputIterator last)//[)左闭右开的区间 { _clear();//先清空再拷贝 while(first != last) { pubshBack(*first);//first进行*引用就取到了里面的data值了 ++first; } }};
3.迭代器失效问题:
4.反向迭代器:
不管是正向迭代器还是反向迭代器,在遍历我们的list中的元素时都是要从begin()所指向的那个节点开始的,然后一个一个往下执行,直到发现当前所指向的那个节点 == end()而结束;
对于反向迭代器而言,我们用begin()开始进行遍历的时候都是访问的是它所指向的下一个节点,在这里可能就比较绕了。这里的下一个节点我们使用”- -“的方式进行访问,那么你一定有疑问了,看图之后“- -”,那么就直接 == end()了,那么遍历才刚开始就结束了吗?当然不是,这里我们要注意,我们的下一个节点是针对正向迭代器而言的,正向迭代器的“- -”,就是反向迭代器的“++”。
代码如下:
充分利用正向迭代器进行函数的复用;
//反向迭代器:template <class Iterator>class ReverIterator{protected: Iterator _current; typedef ReverIterator<Iterator> Self;public: ReverIterator(Iterator cur) :_current(cur) {} Self& operator++()//前置++ { --_current;//运用正向迭代器的--就是反向迭代器的++ return *this; } Self operator++(int)//后置++ { ReverIterator re(_current); --_current; return re; } Self& operator--()//前置-- { ++_current; return *this; } Self operator--(int)//后置-- { ReverIteratr cur(_current); ++_current; return cur; } //typename的意思是强调后面修饰的这个是一个类型,模板类的内嵌类型,用typename强调 typename Iterator::Reference operator*() { Iterator cur = _current; return *(--cur);//访问当前指向的下一个值 } typename Iterator::Pointer operator->() { return &operator*(); } bool operator!=(const Self& cur) { return _current != cur._current; }};
list中增添以下代码: typedef ReverIterator<Iterator> ReIterator; typedef ReverIterator<IteratorConst> ReIteratorConst; ReIterator RBegin() { return ReIterator(End()); } ReIterator REnd() { return ReIterator(Begin()); } ReIteratorConst RBegin() const { return ReIteratorConst(End()); } ReIteratorConst REnd() const { return ReIteratorConst(Begin()); }
阅读全文
0 0
- 剖析容器List
- STL源码剖析(4):容器(list)
- STL源码剖析之序列容器list
- 《STL源码剖析》-序列式容器(二)list容器
- STL源码剖析之List容器【2013.11.18】
- 《STL源码剖析》---list容器insert操作的个人理解
- 《STL源码剖析》---list容器transfer操作个人理解
- STL源码剖析——序列容器之list
- STL源码剖析 - 第4章 序列式容器 - list
- STL学习笔记之容器--list(二)源码剖析
- 【Java基础】--Java容器剖析:Set、List、Map接口
- STL源码剖析——序列容器之list
- 容器剖析
- List 容器
- List 容器
- list容器
- list容器
- list容器
- 【心励路程】----凡事多换位思考
- 基础数据结构04:背包
- 基于机器学习的NLP情感分析(一)---- 数据采集与词向量构造方法(京东商品评论情感分析)
- opencv视频取帧并进行人脸检测(Windows和Linux双版本)
- samba简单免密搭建方式
- 剖析容器List
- CDH启用 sentry
- 51实现定时器定时调整
- 2017暑假集训 div1 匹配问题(1)
- 机器学习实战 笔记 debug(一) kNN
- 单例模式的双层锁原理
- Java GC 相关
- 一个简单的倒计时
- 【c/c++】完成端口服务器中转实现两个客户端之间通信