什么是List
List是STL库(标准模板库)中的一个容器。它的实质上就是一个双向链表,而且要注意的是,这个双向链表是有头的;
这样的设计是STL中一个很巧妙的地方,
它解决了:
(1)插入数据时的判断问题,不用判断链表中有没有数据
(2)实现end()函数的时候仅仅只用一个 _head->_prev就可以找到,不用循环遍历
(3)删除元素的时候也少判断了一个条件
迭代器
这里,我们还要介绍另一个概念,迭代器
所谓迭代器,就是为了让容器的访问可以向指针一样(例如C语言中指针对数组的访问)
对比着来,我们也想实现一个这样的链表
这样表示只是想说明一点:迭代器是为了模拟实现指针的功能才出现的
所以,指针有的迭代器也应该有,比如++,--,解引用,->
指针也可以进行判断大小,所以我们也需要重载 != 、==这些比较符
模拟实现
接下来我们就可以简单模拟实现一下带迭代器的List的大部分功能
List.h
#pragma once
#include<iostream>
using namespace std;
//定义链表节点的结构体
template<typename T>
struct __ListNode
{
__ListNode<T>* _next;
__ListNode<T>* _prev;
T _data;
__ListNode(const T& data)//构建节点的构造函数
:_next(NULL)
, _prev(NULL)
, _data(data)
{}
};
//定义迭代器,模板参数为T,T的引用,T类型的指针
template<typename T, typename Ref, typename Ptr>
struct __ListIterator
{
typedef __ListNode<T> Node;//将链表节点重命名为 Node
typedef __ListIterator<T, T&, T*> self; //将自己的类型重命名为 self,简化命名
Node* _node;
__ListIterator(){}
__ListIterator(Node* node)
:_node(node)
{}
//重载 !=、==操作符
bool operator != (const self& s)
{
return _node != s._node;
}
bool operator == (const self& s)
{
return _node == s._node;
}
//重载 ++、-- 操作符
self& operator ++()
{
_node = _node->_next;
return (self)_node;
}
self operator ++ (int)
{
Node* tmp = _node;
++_node;
return tmp;
}
self& operator --()
{
_node = _node->_prev;
return (self)_node;
}
self operator -- (int)
{
Node* tmp = _node;
--_node;
return tmp;
}
//重载*、->操作符
Ref operator*()
{
return (*_node)._data;
}
Ref operator->()
{
return *_node;
}
};
//定义反向迭代器,模板参数为T,T的引用,T类型的指针
template<typename T, typename Ref, typename Ptr>
struct __ListReverseIterator
{
typedef __ListNode<T> Node;//将链表节点重命名为 Node
typedef __ListReverseIterator<T, T&, T*> self;//将自己的类型重命名为self,简化命名
Node* _node;
__ListReverseIterator()
{}
__ListReverseIterator(Node* node)
:_node(node)
{}
//重载 ++、-- 操作符
self& operator++()
{
_node = _node->_prev;//注意:这里是反向迭代器,++应该指向前一个
//这是反向迭代器最关键的地方
return _node;
}
self operator++(int)
{
Node* tmp = _node;
_node = _node->_prev;
return tmp;
}
self& operator--()
{
_node = _node->_next;
return _node;
}
self operator--(int)
{
Node* tmp = _node;
_node = _node->_next;
return tmp;
}
//重载 !=、==操作符
bool operator==(const self& s)
{
return _node->_data == s._node->_data;
}
bool operator!=(const self& s)
{
return _node->_data != s._node->_data;
}
//重载*、->操作符
Ref operator*()
{
return (*_node)._data;
}
Ref operator->()
{
return *_node;
}
};
//定义链表
template<typename T>
class List
{
typedef __ListNode<T> Node;
public:
typedef __ListIterator<T, T&, T*> Iterator;//重命名为迭代器
typedef __ListReverseIterator<T, T&, T*> ReverseIterator;//重命名为反向迭代器
//申请一个新的节点
Node* BuyNewNode(const T& t)
{
return new Node(t);
}
//构造函数
List()
:_head(BuyNewNode(T()))
{
_head->_next = _head;
_head->_prev = _head;
}
//在尾部插入,删除一个元素
void PushBack(const T& x)
{
Node* tail = _head->_prev;
Node* tmp = BuyNewNode(x);
tail->_next = tmp;
tmp->_prev = tail;
tmp->_next = _head;
_head->_prev = tmp;
}
//定义返回迭代器类型的Begin()和End()
Iterator Begin()
{
return Iterator(_head->_next);
}
Iterator End()
{
return Iterator(_head);
}
//定义返回迭代器类型的rBegin()和rEnd()
ReverseIterator rBegin()
{
return ReverseIterator(_head->_prev);
}
ReverseIterator rEnd()
{
return ReverseIterator(_head);
}
protected:
Node* _head;
};
测试函数
//测试链表
void TestList()
{
List<int> l;
l.PushBack(1);
l.PushBack(2);
l.PushBack(3);
l.PushBack(4);
l.PushBack(5);
//打印l中的元素
List<int> ::Iterator it1 = l.Begin();//定义迭代器it1为l的起始部分
while (it1 != l.End())
{
cout << *it1 << " ";//重载了解引用操作符,可以访问it1中的元素
++it1;//重载了++运算符,可以访问下一个元素
}
cout << endl;
}
void TestReverseIterator()
{
List<int> l;
l.PushBack(1);
l.PushBack(2);
l.PushBack(3);
l.PushBack(4);
List<int>::ReverseIterator it = l.rBegin();//定义反向迭代器it为反向迭代器的第一个元素
while (it != l.rEnd())
{
cout << *it << " ";//重载了解引用操作符,访问元素当前内容
it++;//重载了++运算符,访问后面的元素
}
cout << endl;
}
总结
总结一下,迭代器的出现就是使容器的访问变得可以像指针访问数组那样简便
所以模拟实现迭代器的时候就要重载++,--,->,解引用等运算符,操作符
List是双向循环链表,可以快速的找到末位的元素
注意:第一个元素是_head->_next,End()返回的是_head;_head并不存储元素