STL之list
list简单介绍
- list是STL的一个序列式容器,底层的实现是一个双向链表,每个节点有两个指针分别指向前一个元素和后一个元素
- list在任意位置的插入与删除元素的效率很高,但是它访问元素的效率就相对比较低,它不支持任意位置的访问
list与vector的对比
这里不介绍list的使用,因为它和vector大部分的接口是一样的,不了解vector的可以去看
STL之vector
不同点
- 迭代器失效的问题:vector的迭代器在插入删除时都可能导致迭代器失效但是list在插入时迭代器是不会失效的
- vector访问元素的效率很高它能快速访问任意位置的数据,但是其插入与删除元素的效率极低,而list刚好与之相反
- 需要大量随时访问元素时优先考虑使用vector,而要求插入删除的效率更高时优先考虑list
list的模拟实现
需要的类模板
-
’节点类
// List的节点类template<class T>struct ListNode{ListNode(const T& val = T()):_pPre(nullptr),_pNext(nullptr),_val(val){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;
2.迭代器类
//List的迭代器类template<class T, class Ref, class Ptr>class ListIteratortemplate<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){}ListIterator(const Self& l): _pNode(l._pNode){}//运算符重载 T& operator*(){return _pNode->_val;}T* 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& l){return _pNode != l._pNode;}bool operator==(const Self& l){return _pNode == l._pNode;}PNode _pNode;
为了减少代码的冗余所以将 ListNode*,ListIterator<T, Ref, Ptr>,用typedef进行封装
3.list类
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;private:void CreateHead(){_pHead = new Node;_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;}PNode _pHead;
同意为了减少代码的冗余所以用typedef进行封装
构造与析构
调用接口CreateHead()和push_back()很容易实现构造
list(){CreateHead();}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>& l){CreateHead();// 用l中的元素构造临时的temp,然后与当前对象交换list<T> temp(l.begin(), l.end());this->swap(temp);}list<T>& operator=(list<T> l){this->swap(l);return *this;}~list(){clear();delete _pHead;_pHead = nullptr;}
迭代器
两种迭代器运用函数的重载即可实现
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{PNode cur = _pHead->_pNext;size_t count = 0;while (cur != _pHead){count++;cur = cur->_pNext;}return count;}bool empty()const{return _pHead->_pNext == _pHead;}
获取元素
返回相应值即可
T& front(){return _pHead->_pNext->_val;}const T& front()const{return _pHead->_pNext->_val;}T& back(){return _pHead->_pPre->_val;}const T& back()const{return _pHead->_pPre->_val;}
修改
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()接口
insert的实现
iterator insert(iterator pos, const T& val){Node* pNewNode = new Node(val);Node* pCur = pos._pNode;pNewNode->_pPre = pCur->_pPre;pNewNode->_pNext = pCur;pNewNode->_pPre->_pNext = pNewNode;pCur->_pPre = pNewNode;return iterator(pNewNode);}
首先创建一个的节点Node让它的向前指针指向pos节点的前一个节点,它的向后指针指向pos位置的节点
然后再让pos位置的前一个节点的向后的指针指向新的节点Node,pos位置的向前指针指向新节点Node即可
erase的实现
iterator erase(iterator pos){Node* pDel = pos._pNode;Node* pRet = pDel->_pNext;pDel->_pPre->_pNext = pDel->_pNext;pDel->_pNext->_pPre = pDel->_pPre;delete pDel;return iterator(pRet);}
首先保存被删除节点的指针用pDel保存,因为erase返回的是被删除节点的下一个节点的迭代器所以我们也要将其保存在pRet中,然后就就简单了,将被删节点的后一个节点的向前指针指向被删节点的前一个节点,将被删节点的前一个节点的向后指针指向被删除指针的后面一个节点即可。
void clear(){PNode cur = _pHead->_pNext;while (cur != _pHead){_pHead->_pNext = cur->_pNext;delete cur;cur = _pHead->_pNext;}_pHead->_pNext = _pHead->_pPre = _pHead;}void swap(list<T>& l){std::swap(_pHead, l._pHead);}
clear()遍历list删除即可,swap()用std的swap接口