list的基本结构
list在库中是一个实现删除插入的一个容器, 其中底层的结构是一个双向的循环链表.
链表中的每一个元素都存储在每一个互不相干的独立结点之中. 每一结点中保存了该结点的前一个元素和后一个元素的地址. 对其进行删除插入的操作的时候, 时间复杂度都是O(1);
list不同的地方就在于其迭代器的实现, 由于List中所存储的都是每一个结点的地址,因此对迭代器进行解引用以及++/–操作是需要进行
list的类结构如下(这里我们都采用泛型编程来实现)
template <class T>
class List{
public:
//在这里得LsitNode进行明明
typedef ListNode Nnde;
typedef LsitNode* pNode;
//构造
Lsit(){
_head=new Node;
_head->_next=_head;
_head->_prev=_head;
}
~List(){
if (_head){
pNode cur = _head->_next;
while (cur != _head){
//1.先保存当前结点的下一个结点
//2.删除当前结点
//将保存的下一个结点更新成为当前的结点
pNode next = cur->_next;
delete cur;
cur = next;
}
delete _head;
_head = nullptr;
}
}
private:
//链表中只有一个头结点
LsitNode* _head
}
因为list中是由每一个结点链接而来的, 因此这里也需要对每一个结点进行定义
template <class T>
struct ListNode{
//实现泛型的LsitNode的构造
LsitNode(const T& val=T())
:_data(val);
,_next(nullptr)
,_prev(nullptr)
{}
T _data;
LiatNode<T>* _next;
ListNode<T>* _prev;
}
以上就是list的最基本的底层结构,下面来实现一些其他的基本接口
头插
void pushfront(const T& val){
pNode newnode=new Node(val);
pNode cur=_head->_next;
newNode->_next = _head->_next;
_head->_next->_prev = newNode;
_head->_next = newNode;
newNode->_prev = _head;
}
头删
void PopFront(){
pNode cur = _head->_next;
_head->_next = cur->_next;
cur->_next->_prev = _head;
delete cur;
}
尾插
//尾插
void PushBuck(const T& val){
//申请空间建立心结点
pNode newNode = new Node(val);
pNode cur = _head->_prev;
cur->_next = newNode;
newNode->_next = _head;
_head->_prev = newNode;
newNode->_prev = cur;
}
尾删
//尾插
void PushBuck(const T& val){
//申请空间建立心结点
pNode newNode = new Node(val);
pNode cur = _head->_prev;
cur->_next = newNode;
newNode->_next = _head;
_head->_prev = newNode;
newNode->_prev = cur;
}
注意: 这里是利用最基本的逻辑来实现的插入删除操作, 在实现了insert之后就可以利用insert函数实现以上四个操作
insert(在pos位置插入)
注意:这里的参数传入的是一个迭代器的参数
void Insert(iterator pos, const T& val){
pNode newNode = new Node(val);
pNode cur = pos._node;
newNode->_next = cur;
newNode->_prev = cur->_prev;
cur->_prev->_next = newNode;
cur->_prev = newNode;
}
删除pos位置处的结点,并且返回后一个结点的值
iterator Erase(iterator pos){
if (pos != end()){
pNode cur = pos._node;
pNode next = cur->_next;
pNode prev = cur->_prev;
prev->_next = next;
next->_prev = prev;
delete cur;
pos = iterator(next);
}
return pos;
}
判空
bool Empty() const {
return (_head->_next == _head);
}
获取Lsit的长度
size_t Size()const {
size_t i = 0;
pNode cur = _head->_next;
while (cur != _head){
cur = cur->_next;
++i;
}
return i;
}
清空List
void Clear(){
if (Empty()){
return;
}
pNode cur = _head->_next;
while (cur != _head){
_head->_next = cur->_next;
delete cur;
cur = _head->_next;
}
_head->_next = _head;
_head->_prev = _head;
}
拷贝构造以及赋值运算符的重载
List(const List<T>& lst){
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
auto lit = lst.begin();
while (lit != lst.end()){
PushBuck(*lst);
}
}
List<T>& operator=(const List<T>& lst){
swap(_head, lst._head);
return *this;
}
迭代器的头和尾
iterator begin(){
return iterator(_head->_next);
}
iterator end(){
return iterator(_head);
}
迭代器的封装
这里一共定义了三个模板参数,目的是为了针对解引用以及++操作时让代码看起来不繁琐
template <class T,class Ref,class Ptr>
struct ListInterator{
//在迭代器中封一个结点
typedef ListInterator<T,T&,T*> Self;
ListNode<T>* _node;
ListInterator( ListNode<T>* node)
:_node(node)
{}
//解引用
Ref operator* (){
return _node->_data;
}
Ptr operator-> (){
return &(_node->_data);
}
bool operator!=(const Self& lit){
if (_node != lit._node){
return true;
}
else{
return false;
}
}
bool operator==(const Self& lit){
return _node == lit._node;
}
//前置++
Self& operator++(){
_node = _node->_next;
return *this;
}
//后置++
Self operator++(int){
Self tmp(*this);
_node = _node->_next;
return tmp;
}
};
const迭代器的实现只需要在List的类中就行重命名是进行修改
typedef ListInterator<T,T&,T*> iterator;
typedef ListInterator<T, const T&,const T*> const_iterator;