实现带头循环双向链表
节点
template<class T>
struct ListNode
{
ListNode* _next;
ListNode* _prev;
T _data;
ListNode(const T& val=T())
:_prev(nullptr)
,_next(nullptr)
,_data(val)
{}
};
节点结构体:由于双向链表,所以有_prev 和 _next 两个指针
迭代器
template<class T>
struct _list_iterator
{
typedef ListNode<T> Node;
typedef _list_iterator<T> self;
Node* _node;
_list_iterator(Node* x)
:_node(x)
{}
};
迭代器:成员为Node* 类型
++/--操作
//++it
self& operator++()
{
_node = _node->_next;
return *this;
}
//it++
self operator++(int)
{
self tmp(*this);
_node = _node->_next;
return tmp;
}
//--it
self& operator--()
{
_node = _node->_prev;
return *this;
}
self operator--(int)
{
self tmp(*this);
_node = _node->_prev;
return tmp;
}
注意:后置++需要在参数列表里加一个 int
前置++/--操作: 先++/--,然后在引用,所以直接进行前进后退操作,然后返回*this
后置++/--操作: 先引用,再进行++/--操作,所以需要将之前的值进行拷贝,将原来的进行前进后退操作,再返回之前拷贝的self
解引用操作
T& operator*()
{
return _node->_data;
}
解引用:直接返回节点中存的 _data 值
== / !=操作
bool operator!=(const self& s)
{
return _node != s._node;
}
bool operator==(const self& s)
{
return _node == s._node;
}
成员函数 成员变量
class list
{
typedef ListNode<T> Node;
public:
typedef _list_iterator<T> iterator;
private:
Node* _head;
};
由于是链表,所以只需要存头节点就可以控制整个链表
begin( )/end( )
iterator begin()const
{
return _head->_next;
}
iterator end()const
{
return _head;
}
带头循环双向链表:begin( )返回头节点的下一个节点
end( )返回头节点
swap
void swap(list<T>& tmp)
{
std::swap(_head, tmp._head);
}
一个链表只需要有_head 节点就可以控制整条链表,所以交换两个链表只需要交换头节点就可以了
构造
list()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
只需要控制头节点就可以了,所以我们的构造函数只需要开一个头节点,
我们还需要保持 链表带头双向循环的特点 所以让头节点的_next和_prev都指向自己
析构
clear( )/~list( )
~list()
{
clear();
delete _head;
_head = nullptr;
}
void clear()
{
iterator cur = begin();
while (cur != end())
cur = erase(cur);
}
1.首先说clear ( ) :利用cur节点 来遍历整个链表,依次调用erase( )函数,最后就可以只剩_head节点没有清楚( erase 函数会在后边删除节点中提到 )
2.析构:首先调用clear( ) 先把所有节点全部清空, 然后把头节点的空间回收,最后滞空_head节点就可以完成整个链表的清除
插入
push_back( )
void push_back(const T& x)
{
Node* newnode = new Node(x);
Node* tail = _head->_prev;
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;
//insert(--end(), x);
}
先申请一个新节点,插入到头节点_head的前边 先让 tail 节点连接上新节点 再把_head 连接上新节点,然后把新节点的前驱后继指针连接上前后节点完成插入
void push_front(const T& x)
{
Node* newnode = new Node(x);
Node* front = _head->_prev;
front->_prev = newnode;
newnode->_next = front;
newnode->_prev = _head;
_head->_next = newnode;
//insert(end(), x);
}
前插 道理与尾插相似直接连接就可以了
iterator insert(iterator pos, const T& x)
{
Node* cur = pos._node;
Node* newnode = new Node(x);
newnode->_next = cur->_next;
cur->_next->_prev = newnode;
cur->_next = newnode;
newnode->_prev = cur;
return iterator(newnode);
}
插入 将新节点插入到pos后边就可以了,我们需要找到pos的后一个节点,进行连接,完成插入
有了insert之后,之前的push_back( ) 和 push_front( )都可以复用insert( )
删除
erase( )
iterator erase(iterator pos)
{
assert(pos != end());
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = next;
next->_prev = prev;
delete cur;
return next;
}
由于我们需要头节点来控制整个链表,所以头节点不能被删除,这里暴力断言一下
只需要找到要被删除的节点的前一个节点,后一个节点,这里是双向链表,所以易如反掌
直接进行指针的赋值就可以 最后将要删除的节点释放空间 滞空,完成删除操作
void pop_back()
{
//Node* del = _head->_prev->_prev;
//del->_prev->_next = _head;
//_head->_prev = del->_prev;
//
//delete del;
//del = nullptr;
erase(--end());
}
void pop_front()
{
erase(begin());
}
同样的 和头插 尾插一样,头删和尾删也可以复用erase( )