模板类模拟实现List
2017-03-16 09:57
239 查看
上一篇中我模拟实现了vector,接着这个当然就是list了,首先对于list,在库函数里面,list是一个双向的,即既含有next域,也含有prev域,每个节点都含有这样的结构,我们在写的时候要把一个一个链接上,而且要保证逻辑正确,作者本人就在拷贝构造函数的时候懵逼了半天。所以一个表示节点的结构体必须有,这个当然也可以用类,但是你会感觉本质上你还是用类中结构体的性质,所以还是结构体方便一点。
这个想必大家都很熟悉,所以我就不多说了,然后为了更好、更快捷、明了的表示一个节点,或者是对这个节点做一些操作,我们最好在封装一个类,确实,我是按库里面写的,库里也包含了这个类,采用了迭代器的用法,目前,我们只当迭代器是一个指针,这样才能更直观的理解我们现在的用法。
和库里面一样,我也把很多类型名定义成自己顺手的自定义类型。
最后就该到list的模板类了,这才是重中之重,我也是到这里迷失了一段时间,一个函数改了好久,几近崩溃(小白吐槽而已)。不说了,对这代码再给你说说我的逻辑。
//无参的构造函数,当然一进去就要先开辟好空间
//等着其他的函数什么调用的时候有插入、删除的空间
//并且要构成一个环,
这个函数让我很是尴尬,我的思维逻辑很清晰,在这个函数出错的时候,我还专门找人讨论我的逻辑,绝对没毛病,但是就是有问题,索性放着美观,过了一天,早上打开又理了一次,一次就出来了。所以我get到了一个技能,有时候,歇一歇,放松一下对自己也有帮助。
示意图:
插入一个节点
插入两个节点
以此类推,每次进来先和尾节点的next域相连,然后把新节点的prev域指向尾节点,还要记得的是,一定要和头结点相连,即上述操作完成之后,将新节点的next域指向头结点,将头结点的prev域指向尾节点,这样才是一个循环的双向链表,假如你本意不循环的话,让我没说,但是记得你的节点的netx域要指空。
赋值运算符的操作没啥说的,和拷贝构造的一样,多加个返回值而已,最起码这个函数是这样。逻辑都是一样的。
删除节点的图解:
template<class T> struct ListNode { ListNode(const T& x = T()) //构造函数,给_prev,_next,_value初始化 : _prev(0) , _next(0) , _value(x) { } ListNode<T>* _prev; ListNode<T>* _next; T _value; };
这个想必大家都很熟悉,所以我就不多说了,然后为了更好、更快捷、明了的表示一个节点,或者是对这个节点做一些操作,我们最好在封装一个类,确实,我是按库里面写的,库里也包含了这个类,采用了迭代器的用法,目前,我们只当迭代器是一个指针,这样才能更直观的理解我们现在的用法。
和库里面一样,我也把很多类型名定义成自己顺手的自定义类型。
template<class T, class Ref, class Ptr> struct __ListIterator__ { typedef __ListIterator__<T, T&, T*> Iterator; typedef __ListIterator__<const T, const T&, const T*> ConstItrator; typedef __ListIterator__<T, Ref, Ptr> Self; typedef T ValueType; typedef Ref Reference; typedef Ptr Pointer; typedef ListNode<T>* LinkType; typedef size_t SizeType; LinkType _node; public: __ListIterator__(LinkType x) :_node(x) { } __ListIterator__() :_node(0) { } __ListIterator__(const Iterator& x) :_node(x._node) { } bool operator==(const Iterator& x) { return x._node == _node; } bool operator!=(const Iterator& x) { return x._node != _node; } Reference operator*() { return _node->_value; } Pointer operator->() { return &(*(_node->_value)); } Self& operator++() { _node = _node->_next; return *this; } Self operator++(int) { Self temp(*this); _node = _node->_next; return temp; } Self& operator--() { _node = _node->_prev; return *this; } Self operator--(int) { Self temp(*this); _node = _node->_prev; return temp; } };
最后就该到list的模板类了,这才是重中之重,我也是到这里迷失了一段时间,一个函数改了好久,几近崩溃(小白吐槽而已)。不说了,对这代码再给你说说我的逻辑。
template<class T> class List { public: typedef ListNode<T> Node; typedef T ValueType; typedef ValueType* Pointer; typedef const ValueType* ConstPointer; typedef ValueType& Reference; typedef const ValueType& ConstReference; typedef Node* LinkType; typedef size_t SizeType; typedef __ListIterator__<T, T&, T*> Iterator; typedef __ListIterator__<const T, const T&, const T*> ConstIterator;
//无参的构造函数,当然一进去就要先开辟好空间
//等着其他的函数什么调用的时候有插入、删除的空间
//并且要构成一个环,
List<T>() { _node = new Node; _node->_next = _node; _node->_prev = _node; _node->_value = 0; }
这个函数让我很是尴尬,我的思维逻辑很清晰,在这个函数出错的时候,我还专门找人讨论我的逻辑,绝对没毛病,但是就是有问题,索性放着美观,过了一天,早上打开又理了一次,一次就出来了。所以我get到了一个技能,有时候,歇一歇,放松一下对自己也有帮助。
List<T>(const List<T>& l) { _node = new Node;//给this的_node先开辟好空间 LinkType MoveNode = _node;//然后新定义一个节点,表示尾节点 LinkType srcNode = new Node; srcNode = l._node;//创建一个节点,表示被拷贝对象的头结点 LinkType destNode = new Node;//创建新节点,用来储存拷贝节点的数据,再链接到尾节点上 while (srcNode->_next != l._node)//当l的最后一个节点被拷贝完后,停止拷贝 { destNode = new Node;//每次进去:开辟空间->储存数具->链接上尾节点 MoveNode->_next = destNode; destNode->_prev = MoveNode; destNode->_next = _node; _node->_prev = destNode; srcNode = srcNode->_next; MoveNode = MoveNode->_next; } }
示意图:
插入一个节点
插入两个节点
以此类推,每次进来先和尾节点的next域相连,然后把新节点的prev域指向尾节点,还要记得的是,一定要和头结点相连,即上述操作完成之后,将新节点的next域指向头结点,将头结点的prev域指向尾节点,这样才是一个循环的双向链表,假如你本意不循环的话,让我没说,但是记得你的节点的netx域要指空。
赋值运算符的操作没啥说的,和拷贝构造的一样,多加个返回值而已,最起码这个函数是这样。逻辑都是一样的。
List<T>& operator=(const List& l) { _node = new Node; LinkType MoveNode = _node; LinkType srcNode = new Node; srcNode = l._node; LinkType destNode = new Node; while (srcNode->_next != l._node) { destNode = new Node; destNode->_value = srcNode->_next->_value; MoveNode->_next = destNode; destNode->_prev = MoveNode; destNode->_next = _node; _node->_prev = destNode; srcNode = srcNode->_next; MoveNode = MoveNode->_next; } return *this; }
Iterator Insert(Iterator pos, const T& x) //插入函数,在pos位置的前面插入 { LinkType temp = new Node(x); pos._node->_prev->_next = temp; temp->_prev = pos._node->_prev; temp->_next = pos._node; pos._node->_prev = temp; return temp; }
删除节点的图解:
Iterator Erase(const T& value) { Iterator pos = Find(value); Iterator temp = pos; temp++; pos._node->_prev->_next = pos._node->_next; pos._node->_next->_prev = pos._node->_prev; delete pos._node; return temp; } Iterator Begin() { return _node->_next; } ConstIterator Begin()const { return _node->_next; } Iterator End() { return _node; } ConstIterator End()const { return _node; } bool Empty()const { return Begin() == End(); } SizeType Size() { SizeType size = 0; Iterator temp = Begin(); while (temp._node != _node) { temp._node = temp._node->_next; size++; } return size; } Reference Front() { return _node->_next->_value; } ConstReference Front()const { return _node->_next->_value; } Reference Back() { return _node->_prev->_value; } ConstReference Back()const { return _node->_prev->_value; } void PushFront(const T& x) { Insert(Begin(), x); } void PushBack(const T& x) { Insert(End(), x); } void PopFront() { Delete(_node->_next); } void PopBack() { Delete(_node->_prev); } void Delete(Iterator pos) { Iterator temp = pos; temp._node->_prev->_next = temp._node->_next; temp._node->_next->_prev = temp._node->_prev; delete temp._node; } void Clear() { while (Begin() != End()) { Delete(Begin()); } _node->_next = _node; _node->_prev = _node; _node->_value = 0; } ~List() { Iterator temp; Clear(); } friend ostream& operator<<(ostream& os, List<T>& L) { Iterator temp = L.Begin(); Iterator END = L.End(); while (temp._node != END._node) { cout << temp._node->_value << " "; temp._node = temp._node->_next; } return os; } protected: Iterator Find(const T& value) { Iterator temp = _node; while (temp._node->_value != value) { temp._node = temp._node->_next; } return temp; } private: LinkType _node; };
相关文章推荐
- List模板类实现回文判断
- 循环双链表之Java实现(模拟JDK中LinkedList)
- 数据结构::模拟STL实现list
- STL-模拟实现List
- STL容器中list与迭代器iterator的模拟实现
- c#利用链表模拟实现泛型集合List﹤T﹥
- 模拟实现STL下的list容器
- 【STL】 list的应用及模拟实现
- 【c++模板】模拟实现有模板的双向链表(List)(声明和定义分离)
- JAVA容器-模拟LinkedList实现(双链表)
- 使用模板类,实现用两个栈模拟队列的功能
- [Java]ArrayList与LinkedList的模拟实现
- 使用模板类实现List容器&迭代器
- 【STL】list的应用模拟实现
- Java中使用HashMap,TreeSet和List来实现模拟斗地主的洗牌和发牌的小例子
- 17-3:用LinkedList模拟(实现)队列
- Java基础课程学习总结,使用LinkedList简单模拟队列数据结构和堆栈数据结构的实现
- 使用java.util.LinkedList模拟实现内存页面置换算法--LRU算法
- C++::模拟实现List
- 以模板模拟实现List容器