?
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????????????🎬慕斯主頁:修仙—別有洞天
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????? ??今日夜電波:リナリア—まるりとりゅうが
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0:36━━━━━━?💟──────── 3:51
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????🔄 ? ?? ? ? ? ?? ? ???
??????????????????????????????????????💗關注👍點贊🙌收藏您的每一次鼓勵都是對我莫大的支持😍
目錄
一、list實際的底層原理
二、list的模擬實現
? ? ? ? ?寫在前面
各層封裝的實現
????????節點類
? ? ? ? 迭代器類?
? ? ? ? list類?
list類詳解?
? ? ? ? 迭代器實現
list的修改操作
? ? ? ? Insert?
????????erase
????????swap?
? ? ? ? 復用操作(push_back/front、pop_back/front、clear)
list的構造
? ? ? ? 建立頭節點
????????構造函數
? ? ? ? 拷貝構造和‘=’重載
? ? ? ? 析構函數?
list的空間管理
list的訪問相關
三、整體代碼?
一、list實際的底層原理
????????C++的STL庫中的list是使用帶頭的雙向循環鏈表實現的。list中存儲的每個元素包含了兩個指針,一個指向前一個節點,一個指向后一個節點,這樣就可以方便地在list中進行插入和刪除操作,這些操作的時間復雜度都是O(1)。
?????????大致的結構如下:?
? ? ? ? ?如多大家對于這個數據結構不太熟悉的話,不妨看看作者之前寫的一篇關于帶頭雙向循環鏈表的文章:🌀【數據結構】—C語言實現雙向鏈表(超詳細!)?
二、list的模擬實現
? ? ? ? ?寫在前面
? ? ? ? list的底層雖然是帶頭雙向循環鏈表,但是對于它的實際實現不只是簡單的鏈表而已,當然了,我們肯定會有鏈表的數據結構。但是,這個“結構”,經過了三層的封裝才得以實現,分別是:??第一層:list的節點類
? ? ? ? ? ? ? ? 第二層:list的迭代器類
? ? ? ? ? ? ? ? 第三層:list類
????????本文目前只實現正向的迭代器,反向迭代器會在后面的文章統一vector、string、list一起實現。
各層封裝的實現
?????????節點類
? ? ? ? 主要是包括:對于兩個雙向指針的定義以及數據的定義,再是通過初始化列表對于節點的初始化。
// List的節點類template<class T>struct ListNode{ListNode(const T& val = T())//通過初始化列表初始化值:_val(val), _pPre(nullptr), _pNext(nullptr){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;};
? ? ? ? 迭代器類?
? ? ? ? ?迭代器實際上是對于指針進行操作,因此我們實例化并且重新命名了節點類的指針PNode,由于迭代器分為是否常量正向迭代器,對此我們額外定義了兩個模板參數Ref、Ptr用于控制其中重載運算符 T& operator*() 和?T* operator->()。后面的list類中會有體現。在迭代器中,其中,operator*和operator->返回指向節點的指針,operator++和operator--實現前后綴++/--運算符,operator==和operator!=用來比較兩個迭代器是否指向同一個節點。
//List的迭代器類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){}ListIterator(const Self& l):_pNode(l._pNode){}T& operator*(){return _pNode->_val;}T* operator->(){return &*this;}Self& operator++(){_pNode = _pNode->_pNext;return *this;}Self operator++(int){Self temp(*this);_pNode = _pNode->_pNext;return temp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){Self temp(*this);_pNode = _pNode->_pPre;return temp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return !(*this != l);}private:PNode _pNode;};
? ? ? ? list類?
? ? ? ? 這里先給出主要的封裝,具體的實現后面詳解。可以看到我們又對于節點類進行了實例化并且重新命名,并且定義了一個數據變量。下面是重點了:我們對于迭代器類也進行了實例化并且重新命名,特別是對于上面我們所提到的Ref和Ptr是有做變動的注意看:對于是否常量正向迭代器分別做出了如下定義:T&, T*和const T&, const T*。這里所這的一些變動也是為了后續簡化代碼,避免我們因為動靜態多一份代碼。
????????請結合上面我們迭代器類中我們所提到的operator==和operator!=理解。
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://...private:PNode _pHead;};
list類詳解?
? ? ? ? 在C++中我們通常會進行各類函數的復用,以減少代碼量和增加可讀性。對此,我們盡量做到復用。
? ? ? ? ?迭代器實現
? ? ? ? 返回頭以及尾的迭代器,注意區分動靜態?。
// List Iteratoriterator 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);}
?list的修改操作
? ? ? ? Insert?
? ? ? ? ?實現在pos位置前插入值為val的節點,開辟空間->保存原位置節點->新節點的前指針指向原節點的前一個節點->后節點指向原節點->該邊原節點的前一個節點的后指針指向,指向新節點->原節點的前指針指向新節點->返回性節點的迭代器。
// 在pos位置前插入值為val的節點iterator insert(iterator pos, const T& val){PNode pNewNode = new Node(val);PNode pCur = pos._pNode;pNewNode->_pPre = pCur->_pPre;pNewNode->_pNext = pCur;pNewNode->_pPre->_pNext = pNewNode;pCur->_pPre = pNewNode;return iterator(pNewNode);}
?????????erase
?????????刪除pos位置的節點,返回該節點的下一個位置,保存刪除j節點,保存原節點的下一個節點(用于返回)->一些列刪除解鏈接操作->返回原節點的下一個節點的迭代器
// 刪除pos位置的節點,返回該節點的下一個位置iterator erase(iterator pos){PNode pDel = pos._pNode;PNode pRet = pDel->_pNext;pDel->_pPre->_pNext = pDel->_pNext;pDel->_pNext->_pPre = pDel->_pPre;delete pDel;return iterator(pRet);}
????????swap?
void swap(list<T>& l){pNode tmp = _pHead;_pHead = l._pHead;l._pHead = tmp;}
? ? ? ? ?復用操作(push_back/front、pop_back/front、clear)
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());}void clear(){iterator p = begin();while (p != end()){p = erase(p);}_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;}
?list的構造
? ? ? ? ?建立頭節點
? ? ? ? 因為我們在構造、?拷貝等很多的場景中都會用到對于頭結點的初始化,對此額外寫一個函數用于減少代碼量。
void CreateHead(){_pHead = new Node;_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;}
?????????構造函數
? ? ? ? 實現無參、含參初始化、迭代器構造。
// List的構造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();list<T> temp(l.begin(), l.end());this->swap(temp);}list<T>& operator=(const list<T> l){this->swap(l);return *this;}
? ? ? ? 析構函數?
~list(){clear();delete _pHead;_pHead = nullptr;}
?list的空間管理
size_t size()const{size_t size = 0;ListNode* p = _pHead->_pNext;while (p != _pHead){size++;p = p->_pNext;}return size;}bool empty()const{return size() == 0;}
list的訪問相關
? ? ? ? 主要還是要區分是否為動靜態相關。
T& front(){assert(!empty());return _pHead->_pNext->_val;}const T& front()const{assert(!empty());return _pHead->_pNext->_val;}T& back(){assert(!empty());return _pHead->_pPre->_val;}const T& back()const{assert(!empty());return _pHead->_pPre->_val;}
三、整體代碼?
#pragma once
#include<iostream>
#include<assert.h>using namespace std;namespace lt
{// List的節點類template<class T>struct ListNode{ListNode(const T& val = T())//通過初始化列表初始化值:_val(val), _pPre(nullptr), _pNext(nullptr){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;};//List的迭代器類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){}ListIterator(const Self& l):_pNode(l._pNode){}T& operator*(){return _pNode->_val;}T* operator->(){return &*this;}Self& operator++(){_pNode = _pNode->_pNext;return *this;}Self operator++(int){Self temp(*this);_pNode = _pNode->_pNext;return temp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){Self temp(*this);_pNode = _pNode->_pPre;return temp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return !(*this != l);}private:PNode _pNode;};//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;//靜態迭代器重命名public:///// List的構造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();list<T> temp(l.begin(), l.end());this->swap(temp);}list<T>& operator=(const list<T> l){this->swap(l);return *this;}~list(){clear();delete _pHead;_pHead = nullptr;}///// List Iteratoriterator 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);}///// List Capacitysize_t size()const{size_t size = 0;ListNode* p = _pHead->_pNext;while (p != _pHead){size++;p = p->_pNext;}return size;}bool empty()const{return size() == 0;}// List AccessT& front(){assert(!empty());return _pHead->_pNext->_val;}const T& front()const{assert(!empty());return _pHead->_pNext->_val;}T& back(){assert(!empty());return _pHead->_pPre->_val;}const T& back()const{assert(!empty());return _pHead->_pPre->_val;}// List Modifyvoid 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());}// 在pos位置前插入值為val的節點iterator insert(iterator pos, const T& val){PNode pNewNode = new Node(val);PNode pCur = pos._pNode;pNewNode->_pPre = pCur->_pPre;pNewNode->_pNext = pCur;pNewNode->_pPre->_pNext = pNewNode;pCur->_pPre = pNewNode;return iterator(pNewNode);}// 刪除pos位置的節點,返回該節點的下一個位置iterator erase(iterator pos){PNode pDel = pos._pNode;PNode pRet = pDel->_pNext;pDel->_pPre->_pNext = pDel->_pNext;pDel->_pNext->_pPre = pDel->_pPre;delete pDel;return iterator(pRet);}void clear(){iterator p = begin();while (p != end()){p = erase(p);}_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;}void swap(list<T>& l){pNode tmp = _pHead;_pHead = l._pHead;l._pHead = tmp;}private:void CreateHead(){_pHead = new Node;_pHead->_pPre = _pHead;_pHead->_pNext = _pHead;}PNode _pHead;};
};
????????????????????????感謝你耐心的看到這里?( ′・?・` )比心,如有哪里有錯誤請踢一腳作者o(╥﹏╥)o!?
????????????????????????????????? ? ? ?
?????????????????????????????????????????????????????????????????????????給個三連再走嘛~??