<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
list模擬實現主要包括四個類:節點類、迭代器類、反向迭代器類、list類。
list底層結構:
因為list的底層空間不連續,所以迭代器不能使用原生態的指標,將節點型別的指標封裝成類,過載解除參照及自增等常用操作。list可以儲存多種資料型別,所以這些類都寫成類別範本
list底層是帶頭結點的雙向迴圈連結串列,先實現節點類,給成類別範本的形式,便於插入不同型別的資料。
template<class T> struct ListNode { ListNode<T>* prev; ListNode<T>* next; T data;//要在連結串列中儲存的資料型別 ListNode(const T& value = T()) :prev(nullptr) , next(nullptr) , data(value) { } };
定義新節點的方法:
ListNode<變數型別>*變數名=new ListNode(value);
迭代器類別範本有三個引數
Ref和Ptr一般不寫成T&和T*。
迭代器類的成員變數就是節點型別的指標
Node* _pNode;//成員變數,節點型別指標
編譯器預設的建構函式是無參的,建構函式需要給出
ListIterator(Node* pNode = nullptr) :_pNode(pNode) {}
返回節點中儲存的資料
Ref operator*() { return _pNode->data; }
返回節點中儲存的資料的地址
Ptr operator->() { return &_pNode->data; }
->的過載只對內建型別有意義:
前置++
返回值是迭代器自身型別的參照,前面已經將ListIterator<T, Ref, Ptr>重新命名位Self,表示迭代器自身的型別。
Self& operator++() { _pNode = _pNode->next; return *this; }
後置++
定義臨時變數,返回自增前的值
Self operator++(int) { Self temp(*this); _pNode = _pNode->next; return temp; }
“–”
與++原理相同
Self& operator--() { _pNode = _pNode->prev; return (*this); } Self operator--(int) { Self temp(*this); _pNode = _pNode->prev; return temp; }
比較兩個迭代器中封裝的指標
bool operator!=(const Self& it) { return _pNode != it._pNode; } bool operator==(const Self& it) { return _pNode == it._pNode; }
反向迭代器可以對迭代器類進行復用
因為類外存取靜態成員變數時也會使用類名::變數名的方式,所以對迭代器類中的Reference和Pointer進行重新命名時要加上typename,明確告訴編譯器要重新命名的是一個資料型別。否則編譯器會報錯:
反向迭代器對迭代器類進行復用
private: Iterator _it;//正向迭代器
反向迭代器的解除參照要做特殊處理,返回的是對迭代器–的值
Reference operator*() { //*做特殊處理,先--,再解除參照返回 auto temp = _it; --temp; return *temp; }
複用*的過載,返回value的地址
Pointer operator->() { return &(operator*()); }
反向迭代器的++即為正向迭代器的–
Self operator++() { --_it; return *this; } Self operator++(int) { Self temp(*this); --_it; return *this; }
反向迭代器的–用正向迭代器的++替代
Self operator--() { ++_it; return *this; } Self operator--(int) { Self temp(*this); ++_it; return temp; }
比較反向迭代器類中儲存的正向迭代器,複用正向迭代器中的比較方法
bool operator==(const Self& rit) { return _it == rit; } bool operator!=(const Self& rit) { return _it == rit._it; }
list的成員變數只有一個head指標,指向連結串列的第一個節點
private: Node* head;
空物件
list() { CreatHead(); }
創造頭節點的方法:
//提供一個創造頭結點的方法 void CreatHead() { //呼叫節點類的構造方法 head = new Node(); head->next = head; head->prev = head; }
0000000
new申請空間,令head指向這段空間,head的next和prev都指向自己。
n個T型別元素
呼叫push_back方法,創造頭節點後,不斷進行尾插直到元素個數等於n
list(int n, const T& value = T()) { CreatHead(); for (int i = 0; i < n; ++i) { push_back(value); } }
拷貝構造
複用push_back
list(const list<T>& l) { CreatHead(); auto it = l.cbegin(); while (it != l.cend()) { push_back(*it); it++; } }
迭代器構造
將迭代器構造方法寫成函數模板,可以傳入不同型別的迭代器來構造list物件
template<class InputIterator> list(InputIterator first, InputIterator last) { CreatHead(); while (first != last) { push_back(*first); first++; } }
賦值運運算元過載
與拷貝構造寫法相同
list<T>& operator=(const list<T>& l) { if (this != &l) { clear();//先清空當前物件中的節點 auto it = l.cbegin(); while (it != l.cend()) { push_back(*it); it++; } } return *this; }
解構
清空當前物件,釋放頭節點空間,將頭節點置空
~list() { clear(); delete head; head = nullptr; }
正向迭代器
begin
此處的iterator是對ListIterator<T, T&, T*>的重新命名,這裡會返回一個ListIterator<T, T&, T*>類物件
iterator begin() { //iterator it(head->next); //return it; //head->next是傳遞給迭代器類物件建構函式的引數,呼叫iterator的建構函式 return iterator(head->next);//構造匿名物件返回 }
end
iterator end() { return iterator(head); }
const型別迭代器
iterator和const_iterator 是兩個不同的類:
兩者使用的是相同的類別範本,但是傳遞的引數不同,最終範例化的也是不同的類。
cbegin&cend
const_iterator cbegin()const { return const_iterator(head->next); } const_iterator cend()const { return const_iterator(head); }
rbegin&rend
返回正向迭代器的end和begin
reverse_iterator rbegin() { return reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); }
crbegin&crend
複用正向迭代器的cend和cbegin
const_reverse_iteraotr crbegin()const { return const_reverse_iteraotr(cend()); } const_reverse_iteraotr crend()const { return const_reverse_iteraotr(cbegin()); }
size
遍歷連結串列,統計節點個數
size_t size() { auto it = cbegin(); size_t count = 0; while (it != cend()) { ++count; ++it; } return count; }
empty
如果head->next是head本身則表明連結串列為空
bool empty() { return head->next == head; }
resize
改變節點個數,若新的節點個數大於舊的,則呼叫push_back填充元素;若新的節點個數小於原來的呼叫pop_back尾刪
front
複用迭代器解除參照的方法,返回begin()位置元素
T& front() { return *begin(); } const T& front()const { return *cbegin(); }
back
back表示最後一個元素,但是end()指向的是最後一個元素的下一個位置,需要定義臨時變數,不能直接對end()進行- -。
T& back() { auto it = end(); //return --end()//錯誤寫法 it--; return *it; } const T& back()const { auto it = end(); it--; return *it; }
定義一個列印連結串列的函數模板,檢驗方法。通過迭代器遍歷連結串列,列印每一個節點的資料。
template<class T> void PrintList(const list<T>& l) { auto it = l.cbegin(); while (it != l.cend()) { cout << *it << " "; ++it; } cout << endl; }
尾插與尾刪
push_back
複用insert方法在end位置插入
void push_back(const T& value) { insert(end(), value); }
pop_back
先判斷連結串列是否為空,複用erase方法在end的前一個位置進行插入
void pop_back() { if (empty()) { return; } auto it = end(); it--; erase(it); }
複用insert與erase方法,在begin()位置進行插入或刪除
void push_front(const T& value = T()) { insert(begin(), value); } void pop_front() { erase(begin()); }
⭐insert
任意位置的插入:申請新節點,連線新節點與連結串列,斷開舊的連線。
這裡傳入的引數是一個迭代器類物件,不能直接進行操作,要對物件中封裝的_pNode指標進行操作。
返回值是新插入的節點的迭代器,所以要用申請的新節點的指標newnode構造一個迭代器類物件返回,不能直接返回newnode
iterator insert(iterator Insertpos, const T& value) { Node* newnode = new Node(value); Node* pos = Insertpos._pNode;//_pNode是節點型別的指標 newnode->next = pos; newnode->prev = pos->prev; newnode->prev->next = newnode; pos->prev = newnode; //return newnode; //⭐迭代器是封裝的Node*指標,此時不能再返回newnode return iterator(newnode);//構造匿名物件返回 }
⭐erase
任意位置的刪除:分別改變前後兩個節點的next和prev指標的指向即可
iterator erase(iterator Erasepos) { Node* pos = Erasepos._pNode; Node* ret = pos->next; pos->prev->next = pos->next; pos->next->prev = pos->prev; delete pos; return iterator(ret); }
區間刪除:複用單個節點刪除的方法,遍歷要刪除的區間。
要用接收erase的返回值,防止迭代器失效
iterator erase(iterator first, iterator last) { auto it = first; while (it != last) { //it=erase(it); //後置++會構造臨時物件返回,不會導致迭代器失效 erase(it++); } return it; }
clear&swap
void clear() { erase(begin(), end()); } void swap(list<T>& l) { std::swap(head, l.head); }
#include<iostream> #include<vector> using namespace std; namespace ZH { / //節點類別範本, template<class T> struct ListNode { ListNode<T>* prev; ListNode<T>* next; T data; ListNode(const T& value = T()) :prev(nullptr) , next(nullptr) , data(value) { } }; / //迭代器類別範本 //list的迭代器不能使用原生態的指標,要進行封裝 //T:迭代器指向的元素型別 //Ref:給operator*使用,返回參照型別,不要寫成T& //Ptr:返回值使用,不要寫成T* template<class T,class Ref,class Ptr> class ListIterator { public: typedef ListNode<T> Node;//化簡節點類的名字 typedef Ref Reference;//在反向迭代器類中使用 typedef Ptr Pointer; typedef ListIterator<T, Ref, Ptr> Self;//簡化迭代器類的名字 //建構函式 ListIterator(Node* pNode=nullptr) :_pNode(pNode) {} //過載部分需要使用的運運算元即可:*、->、++、--、== Ref operator*() { return _pNode->data; } //T為自定義型別時有意義, Ptr operator->() { return &_pNode->data; } //前置++,返回值是迭代器自身型別的參照 Self& operator++() { _pNode = _pNode->next; return *this; } //後置 Self operator++(int) { Self temp(*this); _pNode = _pNode->next; return temp; } Self& operator--() { _pNode = _pNode->prev; return (*this); } Self operator--(int) { Self temp(*this); _pNode = _pNode ->prev; return temp; } //迭代器能進行比較 bool operator!=(const Self& it) { return _pNode != it._pNode; } bool operator==(const Self& it) { return _pNode == it._pNode; } Node* _pNode;//成員變數,節點型別指標 }; //反向迭代器類別範本,對迭代器進行復用 template<class Iterator> class ListReverseIterator { public: //typedef Iterator::Reference Reference; //typedef Iterator::Pointer Pointer; typedef typename Iterator::Reference Reference;//typename指定Reference是Iterator中的資料型別 typedef typename Iterator::Pointer Pointer; typedef ListReverseIterator<Iterator> Self; ListReverseIterator(Iterator it) : _it(it) { } Reference operator*() { //*做特殊處理,先--,再解除參照返回 auto temp = _it; --temp; return *temp; } Pointer operator->() { return &(operator*()); } Self operator++() { --_it; return *this; } Self operator++(int) { Self temp(*this); --_it; return *this; } Self operator--() { ++_it; return *this; } Self operator--(int) { Self temp(*this); ++_it; return temp; } bool operator==(const Self& rit) { return _it == rit; } bool operator!=(const Self& rit) { return _it == rit._it; } private: Iterator _it;//正向迭代器 }; template<class T> class list { typedef ListNode<T> Node; //typedef Node* iterator;//不能使用Node*作迭代器 //迭代器 typedef ListIterator<T, T&, T*> iterator; typedef ListIterator< T, const T&, const T*> const_iterator; typedef ListReverseIterator<iterator> reverse_iterator; typedef ListReverseIterator<const_iterator> const_reverse_iteraotr; public: /// //構造 list() { CreatHead(); } list(int n, const T& value=T()) { CreatHead(); for (int i = 0; i < n; ++i) { push_back(value); } } list(const list<T>& l) { CreatHead(); auto it = l.cbegin(); while (it != l.cend()) { push_back(*it); it++; } } //迭代器區間構造 template<class InputIterator> list(InputIterator first, InputIterator last) { CreatHead(); while (first != last) { push_back(*first); first++; } } //賦值運運算元過載 list<T>& operator=(const list<T>& l) { if (this != &l) { clear();//先清空當前物件中的節點 auto it = l.cbegin(); while (it != l.cend()) { push_back(*it); it++; } } return *this; } ~list() { clear(); delete head; head = nullptr; } public: //迭代器 iterator begin() { //iterator it(head->next); //return it; //iterator是對ListIterator<T, T&, T*>的重新命名 //這裡會返回一個ListIterator<T, T&, T*>類物件 //head->next是傳遞給迭代器類物件建構函式的引數,呼叫iterator的建構函式 return iterator(head->next);//構造匿名物件返回 } iterator end() { return iterator(head); } //const型別迭代器 const_iterator cbegin()const { return const_iterator(head->next); } const_iterator cend()const { return const_iterator(head); } //反向迭代器 //反向迭代器的成員變數是一個迭代器類物件 //end()即為傳遞給反向迭代器類建構函式的引數 reverse_iterator rbegin() { return reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } //反向const型別迭代器 const_reverse_iteraotr crbegin()const { return const_reverse_iteraotr(cend()); } const_reverse_iteraotr crend()const { return const_reverse_iteraotr(cbegin()); } / //容量 size_t size() { auto it = cbegin(); size_t count = 0; while (it != cend()) { ++count; ++it; } return count; } bool empty() { return head->next == head; } void resize(int newsize,const T& value=T()) { size_t oldsize = size(); if (newsize > oldsize) { while (oldsize++<newsize) { push_back(value); } } if (newsize < oldsize) { while (oldsize-- < newsize) { pop_back(); } } } /// //元素存取 T& front() { return *begin(); } const T& front()const { return *cbegin(); } T& back() { auto it = end(); it--; return *it; } const T& back()const { auto it = end(); it--; return *it; } / //元素修改 void push_back(const T& value) { insert(end(), value); } void pop_back() { if (empty()) { return; } auto it = end(); it--; erase(it); } void push_front(const T& value = T()) { //Node* pos = head->next; /*Node* newnode = new Node(value); newnode->next = head->next; newnode->prev = head; head->next->prev = newnode; head->next = newnode;*/ //複用insert insert(begin(), value); } void pop_front() { erase(begin()); } //⭐insert // iterator是ListIterator<T, T&, T*> iterator insert(iterator Insertpos, const T& value) { Node* newnode = new Node(value); Node* pos = Insertpos._pNode;//_pNode是節點型別的指標 newnode->next = pos; newnode->prev = pos->prev; newnode->prev->next = newnode; pos->prev = newnode; //return newnode; //⭐迭代器是封裝的Node*指標,此時不能再返回newnode return iterator(newnode);//構造匿名物件返回 } //⭐erase iterator erase(iterator Erasepos) { Node* pos = Erasepos._pNode; Node* ret = pos->next; pos->prev->next = pos->next; pos->next->prev = pos->prev; delete pos; return iterator(ret); } iterator erase(iterator first, iterator last) { auto it = first; while (it != last) { //it=erase(it); erase(it++); } return it; } void clear() { erase(begin(), end()); } void swap(list<T>& l) { std::swap(head, l.head); } private: //提供一個創造頭結點的方法 void CreatHead() { //呼叫節點類的構造方法 head = new Node(); head->next = head; head->prev = head; } private: Node* head; }; template<class T> void PrintList(const list<T>& l) { auto it = l.cbegin(); while (it != l.cend()) { cout << *it << " "; ++it; } cout << endl; } } void Test1() { ZH::list<int> l1; ZH::list<int> l2(3, 1); PrintList(l2); ZH::list<int> l3(l2.begin(), l2.end()); PrintList(l3); vector<int> v{ 0,1,2,3,4 }; ZH::list<int> l4(v.begin(), v.end()); PrintList(l4); } void Test2() { vector<int> v{ 1,2,3,4 }; ZH::list<int> L1(v.begin(), v.end()); L1.push_back(5); L1.push_back(6); L1.push_front(0); PrintList(L1); L1.pop_back(); L1.pop_front(); PrintList(L1); L1.erase(--L1.end()); PrintList(L1); } void Test3() { ZH::list<int> L1; L1.push_back(1); L1.push_back(2); L1.push_back(3); L1.push_front(0); PrintList(L1); L1.resize(6, 5); PrintList(L1); } struct A { int a; int b; int c; }; void Test4() { A aa{ 1,2,3 }; A bb{ 4,5,6 }; A cc{ 7,8,9 }; ZH::list<A> L; L.push_back(aa); L.push_back(bb); L.push_back(cc); auto it = L.begin(); while (it != L.end()) { //⭐it->得到的是節點的地址 //本應是it->->a,編譯器做了特殊處理 cout << it->a << " "; it++; } cout << endl; } void Test5() { ZH::list<int> L1; L1.push_back(0); L1.push_back(1); L1.push_back(2); L1.push_back(3); PrintList(L1); cout << L1.back() << endl; cout << L1.front() << endl; cout << L1.size() << endl; L1.clear(); cout << L1.size() << endl; } void Test6() { ZH::list<int> L1; L1.push_back(0); L1.push_back(1); L1.push_back(2); L1.push_back(3); PrintList(L1); //區間刪除 /*L1.erase(L1.begin(), L1.end()); PrintList(L1);*/ ZH::list<int> L2; L2.push_back(1); L2.push_back(2); L2.push_back(3); L2.push_back(4); L2.push_back(5); PrintList(L2); L1.swap(L2); PrintList(L1); PrintList(L2); } int main() { Test6(); system("pause"); return 0; }
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45