模板类模拟实现List
来源:互联网 发布:加工中心手动编程铣圆 编辑:程序博客网 时间:2024/05/23 11:01
上一篇中我模拟实现了vector,接着这个当然就是list了,首先对于list,在库函数里面,list是一个双向的,即既含有next域,也含有prev域,每个节点都含有这样的结构,我们在写的时候要把一个一个链接上,而且要保证逻辑正确,作者本人就在拷贝构造函数的时候懵逼了半天。所以一个表示节点的结构体必须有,这个当然也可以用类,但是你会感觉本质上你还是用类中结构体的性质,所以还是结构体方便一点。
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
- 类模板模拟实现STL中List
- 以模板模拟实现List容器
- 【c++模板】模拟实现有模板的双向链表(List)(声明和定义分离)
- <STL>模拟实现List
- C++::模拟实现List
- STL-模拟实现List
- 模拟实现 list
- list模拟实现
- 模拟实现list(迭代器)
- 【STL】模拟实现list
- 模拟实现list(iterator)
- 模拟实现list(迭代器)
- list简单模拟实现
- 模拟实现list
- 集合的模拟实现(类模板)
- 类模板模拟实现STL中Vector
- 模板模拟实现栈
- 【机器学习】GBDT(Gradient Boosting Decision Tree)
- Picasso加载https的图片加载不出来的解决方案
- windows 下使用 virtualenv 创建虚拟环境
- 反射
- 【DayDayUp】【算法_图_强连通_之一_Kosaraju算法和Tarjan算法】
- 模板类模拟实现List
- elasticsearch 配置中文分词
- 算法导论 练习题 2.3-2
- 工厂设计模式
- ibatis中数据库查询与新增语句字段包含关键字的处理
- 关于Qt的杂录
- ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
- C++ 右结合律与左结合律详解
- <c:if test />来判定两个字符串是否相等