因为list是链表,所以先设计一个节点,双向节点。
template<class T>
struct ListNode
{
ListNode(const T& val = T())
: _Pre(nullptr)
, _Next(nullptr)
, _val(val)
{}
ListNode<T>* _Pre;
ListNode<T>* _Next;
T _val;
};
void CreateHead()
{
_phead = new Node;
_phead->_Pre = _phead;
_phead->_Next = _phead;
}
使头结点自己连接自己
刚好也可以设计判空函数:首尾相连就是空
bool empty()
{
return _phead->_Next == _phead->_Pre;
}
接下来是最难的一步了,也是最容易晕的一部分
普通迭代器很简单和之前链表(忘记了,请复习数据结构)的思路一模一样。
template<class Tr>
struct __list_iterator
{
typedef ListNode<T> node;
typedef __list_iterator<T> self;
typedef node* pnode;
pnode _pnode;
__list_iterator(node* n=nullptr)
:_pnode(n)
{
}
__list_iterator(const self& l)
:_pnode(l._pnode)
{
}
T& operator*()
{
return _pnode->_val;
}
T* operator->()
{
return &(operator*());
}
self& operator++()//前置
{
_pnode = _pnode->_Next;
return _pnode;
}
self operator++(int)//后置
{
self tmp = *this;
_pnode = _pnode->_Next;
return tmp;
}
bool operator==(const self& it)
{
return _pnode == it._pnode;
}
bool operator!=(const self& it)
{
return _pnode != it._pnode;
}
//不需要析构,因为node的归属权是属于list的,迭代器只是使用权
};
但是如果我需要const iterator怎么办?
难道再设计一个类命名为const iterator?
当然不是了,这就体现出stl大佬思维的灵活性了。
List 的迭代器
迭代器有两种实现方式,具体应根据容器底层数据结构实现:
template<class T,class Ref,class Ptr>
struct __list_iterator
{
typedef ListNode<T> node;
typedef __list_iterator<T, Ref, Ptr> self;
typedef node* pnode;
pnode _pnode;
__list_iterator(node* n=nullptr)
:_pnode(n)
{
}
__list_iterator(const self& l)
:_pnode(l._pnode)
{
}
Ref operator*()
{
return _pnode->_val;
}
Ptr operator->()
{
return &(operator*());
}
self& operator++()//前置
{
_pnode = _pnode->_Next;
return _pnode;
}
self operator++(int)//后置
{
self tmp = *this;
_pnode = _pnode->_Next;
return tmp;
}
bool operator==(const self& it)
{
return _pnode == it._pnode;
}
bool operator!=(const self& it)
{
return _pnode != it._pnode;
}
//不需要析构,因为node的归属权是属于list的,迭代器只是使用权
};
这个简直神迹一般的代码,因为我不管需要引用还是const引用就会调用Ref就可以了,
需要指针或者const指针,直接调用Ptr就可以了,这些东西都是打包好的。只需要改Ref和Ptr就可以实现调的是不是带const的变量。
有了迭代器就可以实现find 、insert、erase。
只需要再最后\最前插入这也元素就可以了(可以复用insert)
void push_back(const T& x)
{
ListNode<T>* newNode = new ListNode<T>(x);
ListNode<T>* tail = _phead->_Pre;
tail->_Next = newNode;
newNode->_Pre = tail;
newNode->_Next = _phead;
_phead->_Pre = newNode;
}
其实就是erase的复用
iterator find(const T& x)
{
auto it = begin();
while (it != end())
{
if (*it==x) return it;
++it;
}
return it;
}
iterator insert(iterator pos, const T& x)//在pos前面插入
{
Node* NewNode = new Node(x);
Node* cur = pos._pnode;
Node* prev = cur->_Pre;
prev->_Next = NewNode;
NewNode->_Pre = prev;
NewNode->_Next = cur;
cur->_Pre = NewNode;
return iterator(NewNode);
}
bool empty()
{
return _phead->_Next == _phead->_Pre;
}
iterator erase(iterator pos)
{
assert(!empty());
Node* cur = pos._pnode;
Node* prev = cur->_Pre;
Node* next = cur->_Next;
prev->_Next = next;
next->_Pre = prev;
delete cur;
return (iterator)next;
}
//void push_back(const T& val) { insert(begin(), val); }
void pop_back() { erase(--end()); }
void push_front(const T& val) { insert(end(), val); }
void pop_front() { erase(begin()); }