前言:list是带头节点的双向循环链表,本文意在了解list的基本使用,并且模拟实现list。
1.list的基本框架
list是由一个一个的节点,形成的双向带头链表,所以必须实现节点这一结构。
template<class T>
struct ListNode
{
ListNode(const T& val = T())
:_pNext(nullptr),
_pPre(nullptr),
_val(val)
{
}
ListNode<T>* _pPre;
ListNode<T>* _pNext;
T _val;
};
有了节点,再对节点进行链接,就形成了链表。链表中只需要有头节点就可以通过头节点找到其他的节点。
class list
{
typedef ListNode<T> Node;
typedef Node* PNode;
private:
PNode _pHead;
}
实现构造函数,只创造头节点,至于后面的节点插入就好了
list()
{
_pHead = new Node;
_pHead->_pNext = _pHead;
_pHead->_pPre = _pHead;
}
实现push_back(),插入数据
void push_back(const T& val)
{
PNode newnode = new Node(val);
PNode tail = _pHead->_pPre;
_pHead->_pPre = newnode;
tail->_pNext = newnode;
newnode->_pNext = _pHead;
newnode->_pPre = tail;
}
这就是最简易的list实现。
namespace ly
{
template<class T>
struct ListNode
{
ListNode(const T& val = T())
:_pNext(nullptr),
_pPre(nullptr),
_val(val)
{
}
ListNode<T>* _pPre;
ListNode<T>* _pNext;
T _val;
};
template<class T>
class list
{
typedef ListNode<T> Node;
typedef Node* PNode;
public:
list()
{
_pHead = new Node;
_pHead->_pNext = _pHead;
_pHead->_pPre = _pHead;
}
void push_back(const T& val)
{
PNode newnode = new Node(val);
PNode tail = _pHead->_pPre;
_pHead->_pPre = newnode;
tail->_pNext = newnode;
newnode->_pNext = _pHead;
newnode->_pPre = tail;
}
private:
PNode _pHead;
}
}
2.list的具体模拟实现
上述的list功能和STL中的list相差甚远,所以我们需要进一步的完善我们的list。
2.1 list的迭代器实现
vector和string的迭代器是封装的指针,因为它俩是顺序储存,物理地址挨着,所以迭代器的实现和操作都非常的简单。但是list的迭代器呢?它由于物理空间不连续,用指针,将链表串联起来,不支持随机访问。该如何实现它的迭代器呢?这个迭代器如何进行++,解引用等操作呢? 答案是:我们可以创建一个迭代器类,在类中实现迭代器的功能,我们可以重载运算符,对吧?
2.1.1 简易迭代器实现
实现一个简易的迭代器,完成++到下一个节点的功能,以及解引用。
template<class T>
class ListIterator
{
typedef ListNode<T>* PNode;
typedef ListIterator<T> Self;
public:
PNode _pNode;
ListIterator(PNode pNode = nullptr)
:_pNode(pNode)
{
}
Self& operator++()
{
_pNode = _pNode->_pNext;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_pNode = _pNode->_pNext;
return tmp;
}
Self& operator--()
{
_pNode = _pNode->_pPre;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_pNode = _pNode->_pPre;
return tmp;
}
Ref operator*()
{
return _pNode->_val;
}
};
2.1.2 如何支持const版本的迭代器
但是上述的迭代器,如果想要支持const版本的,该如何实现呢? 可能有人说,这不难,我直接再写一个迭代器就好了,里面全换成支持const调用的版本就好了,这个方法可以,但是不要忘了模板参数这个东东。
template<class T,class Ref>
class ListIterator
{
typedef ListNode<T>* PNode;
typedef ListIterator<T,Ref> Self;
public:
PNode _pNode;
ListIterator(PNode pNode = nullptr)
:_pNode(pNode)
{
}
Self& operator++()
{
_pNode = _pNode->_pNext;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_pNode = _pNode->_pNext;
return tmp;
}
Self& operator--()
{
_pNode = _pNode->_pPre;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_pNode = _pNode->_pPre;
return tmp;
}
Ref operator*()
{
return _pNode->_val;
}
};
昂这样就可以了?就改个模板参数?答案是:就是这样,改模板参数,具体使用时,直接对应推导即可。 比如:
typedef ListIterator<T, T&> iterator;
typedef ListIterator<T, const T&> const_iterator;
这样就已经,完成了两个版本。
2.1.3 完整的迭代器
迭代器也是支持 -> ,同样也得支持const版本,所以再添加一个模板参数。总共就是三个参数,查看STL源码时,当然也是三个模板参数。
typedef ListIterator<T, T&,T*> iterator;
typedef ListIterator<T, const T&,const T*> const_iterator;
template<class T, class Ref, class Ptr>
class ListIterator
{
typedef ListNode<T>* PNode;
typedef ListIterator<T, Ref, Ptr> Self;
public:
ListIterator(PNode pNode = nullptr)
:_pNode(pNode)
{
}
Ref operator*()
{
return _pNode->_val;
}
Ptr operator->()
{
return &_pNode->_val;
}
Self& operator++()
{
_pNode = _pNode->_pNext;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_pNode = _pNode->_pNext;
return tmp;
}
Self& operator--()
{
_pNode = _pNode->_pPre;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_pNode = _pNode->_pPre;
return tmp;
}
bool operator!=(const Self& it)
{
return _pNode != it._pNode;
}
bool operator==(const Self& it)
{
return _pNode == it._pNode;
}
PNode _pNode;
};
关于以上对-> 重载,大家可能有疑惑?为什么返回的是一个T*,或者是一个const T*。 也就是说我们调用 iterator it->,返回的是一个指针,所以还得加一个-> 才能达到我们想要的结果,但是由于这样的可读性比较差,所以编译器做了优化,并不需要额外添加-> 。
2.2 list的构造函数
每个list都有一个哨兵位头节点,所以我们写一个创造头节点的函数
void CreateHead()
{
_pHead = new Node();
_pHead->_pNext = _pHead;
_pHead->_pPre = _pHead;
}
2.2.1 list构造函数
list()
{
_pHead = new Node;
_pHead->_pNext = _pHead;
_pHead->_pPre = _pHead;
}
list(int n, const T& value = T())
{
CreateHead();
for (int i = 0; i < n; i++)
{
push_back(value);
}
}
template <class Iterator>
list(Iterator first, Iterator last)
{
CreateHead();
while (first != last)
{
push_back(*first);
++first;
}
}
2.2.2 list的拷贝构造以及= 的重载
list(const list<T>& it)
{
CreateHead();
list<T> tmp(it.begin(), it.end());
std::swap(_pHead, tmp._pHead);
}
list<T>& operator=(list<T> it)
{
std::swap(_pHead, it._pHead);
return *this;
}
拷贝构造的话,直接创建一个临时的list tmp去拷贝 it 的所有节点值,再和this交换头节点就可以了。 赋值重载,用的传值传参,所以直接交换 it 的头节点即可。
2.2.3 迭代器功能实现
typedef ListIterator<T, T&,T*> iterator;
typedef ListIterator<T, const T&,const T*> const_iterator;
iterator begin()
{
return iterator(_pHead->_pNext);
}
iterator end()
{
return iterator(_pHead);
}
const_iterator begin() const
{
return const_iterator(_pHead->_pNext);
}
const_iterator end() const
{
return const_iterator(_pHead);
}
2.2.4 插入和删除操作
iterator insert(iterator pos, const T& val)
{
PNode newnode = new Node(val);
PNode cur = pos._pNode;
PNode pre = cur->_pPre;
cur->_pPre = newnode;
newnode->_pNext = cur;
pre->_pNext = newnode;
newnode->_pPre = pre;
return iterator(newnode);
}
iterator erase(iterator pos)
{
PNode next = pos._pNode->_pNext;
PNode pre = pos._pNode->_pPre;
pre->_pNext = next;
next->_pPre = pre;
delete pos._pNode;
return iterator(next);
}
void push_back(const T& val)
{
insert(end(), val);
}
void pop_back()
{
erase(end());
}
void push_front(const T& val)
{
insert(begin(), val);
}
void pop_front()
{
erase(begin());
}
上面的所有功能都可以复用insert和erase,从这里直观的看出list的插入删除非常高效,只需要改变一下节点的指向关系,就能完成插入,删除,灰常强势。
2.2.5 析构函数
清理资源的话,我们希望实现两种:一种可以清除除了头节点的所有其它节点,另一种则是完成的释放list的所有节点。
void clear()
{
iterator it = begin();
while (it != end())
{
erase(it++);
}
}
void clear()
{
iterator it = begin();
while (it != end())
{
erase(it++);
}
}
2.2.6 其他功能
size_t size() const
{
size_t i = 0;
const_iterator it = begin();
while (it != end())
{
i++;
it++;
}
return i;
}
bool empty()const
{
return _pHead->_pNext == _pHead->_pPre;
}
T& front()
{
return * begin();
}
const T& front()const
{
return *begin();
}
T& back()
{
return *(--end());
}
const T& back()const
{
return *(--end());
}
void Print()
{
for (auto it : *this)
{
std::cout << it << ' ';
}
std::cout << std::endl;
}
3. list模拟实现代码
#include<iostream>
namespace ly
{
template<class T>
struct ListNode
{
ListNode(const T& val = T())
:_pNext(nullptr),
_pPre(nullptr),
_val(val)
{
}
ListNode<T>* _pPre;
ListNode<T>* _pNext;
T _val;
};
template<class T, class Ref, class Ptr>
class ListIterator
{
typedef ListNode<T>* PNode;
typedef ListIterator<T, Ref, Ptr> Self;
public:
ListIterator(PNode pNode = nullptr)
:_pNode(pNode)
{
}
Ref operator*()
{
return _pNode->_val;
}
Ptr operator->()
{
return &_pNode->_val;
}
Self& operator++()
{
_pNode = _pNode->_pNext;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_pNode = _pNode->_pNext;
return tmp;
}
Self& operator--()
{
_pNode = _pNode->_pPre;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_pNode = _pNode->_pPre;
return tmp;
}
bool operator!=(const Self& it)
{
return _pNode != it._pNode;
}
bool operator==(const Self& it)
{
return _pNode == it._pNode;
}
PNode _pNode;
};
template<class T>
class list
{
typedef ListNode<T> Node;
typedef Node* PNode;
public:
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T&> const_iterator;
public:
list()
{
_pHead = new Node;
_pHead->_pNext = _pHead;
_pHead->_pPre = _pHead;
}
list(int n, const T& value = T())
{
CreateHead();
for (int i = 0; i < n; i++)
{
push_back(value);
}
}
template <class Iterator>
list(Iterator first, Iterator last)
{
CreateHead();
while (first != last)
{
push_back(*first);
++first;
}
}
list(const list<T>& it)
{
CreateHead();
list<T> tmp(it.begin(), it.end());
std::swap(_pHead, tmp._pHead);
}
list<T>& operator=(list<T> it)
{
std::swap(_pHead, it._pHead);
return *this;
}
void clear()
{
iterator it = begin();
while (it != end())
{
erase(it++);
}
}
iterator begin()
{
return iterator(_pHead->_pNext);
}
iterator end()
{
return iterator(_pHead);
}
const_iterator begin() const
{
return const_iterator(_pHead->_pNext);
}
const_iterator end() const
{
return const_iterator(_pHead);
}
size_t size() const
{
size_t i = 0;
const_iterator it = begin();
while (it != end())
{
i++;
it++;
}
return i;
}
bool empty()const
{
return _pHead->_pNext == _pHead->_pPre;
}
T& front()
{
return * begin();
}
const T& front()const
{
return *begin();
}
T& back()
{
return *(--end());
}
const T& back()const
{
return *(--end());
}
void push_back(const T& val)
{
insert(end(), val);
}
void pop_back()
{
erase(end());
}
void push_front(const T& val)
{
insert(begin(), val);
}
void pop_front()
{
erase(begin());
}
iterator insert(iterator pos, const T& val)
{
PNode newnode = new Node(val);
PNode cur = pos._pNode;
PNode pre = cur->_pPre;
cur->_pPre = newnode;
newnode->_pNext = cur;
pre->_pNext = newnode;
newnode->_pPre = pre;
return iterator(newnode);
}
iterator erase(iterator pos)
{
PNode next = pos._pNode->_pNext;
PNode pre = pos._pNode->_pPre;
pre->_pNext = next;
next->_pPre = pre;
delete pos._pNode;
return iterator(next);
}
void clear()
{
iterator it = begin();
while (it != end())
{
erase(it++);
}
}
void swap(list<T>& it)
{
PNode tmp = it._pHead;
it._pHead = _pHead;
_pHead = tmp;
}
void Print()
{
for (auto it : *this)
{
std::cout << it << ' ';
}
std::cout << std::endl;
}
private:
void CreateHead()
{
_pHead = new Node();
_pHead->_pNext = _pHead;
_pHead->_pPre = _pHead;
}
PNode _pHead;
};
};
**结尾语:**以上就是list的模拟实现。
|