剖析容器List
2017-07-19 13:11
78 查看
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()); }
相关文章推荐
- STL源代码剖析 容器 stl_list.h
- STL源码剖析——序列容器之list
- STL 源码剖析读书笔记三:序列式容器之 vector、list
- STL源码剖析之序列容器list
- STL学习笔记之容器--list(二)源码剖析
- STL源码剖析之序列式容器list
- STL源码剖析之List容器【2013.11.18】
- 【Java基础】--Java容器剖析:Set、List、Map接口
- java 容器类使用 Collection,Map,HashMap,hashTable,TreeMap,List,Vector,ArrayList的区别
- Java容器(二)——「ArrayList、LinkedList性能测试与分析」
- Java中的容器类List、Set、Map的对比
- 几种常见 容器 比较和分析 hashmap, map, vector, list ...hash table
- [Sencha ExtJS6 Modern] 改进bug: 当容器(如Container/Panel/List)内容未超出容器高度时, Scroller无法上/下拉(即越界滚动)
- JAVA的容器---List,Map,Set
- ACM: STL标准库容器的应用(vector、queue、list、map)
- docker技术剖析--docker网络(二)docker宿主机之间容器互通 for centos7.2
- 【Java集合源码剖析】LinkedList源码剖析
- 【转载】C++三种容器:list、vector和deque的区别
- Java容器(List、Map、Set、Iterator)
- STL学习笔记之 (五)容器 vector deque list 使用条件