莆田房產(chǎn)網(wǎng)網(wǎng)站如何做關(guān)鍵詞優(yōu)化
文章目錄
- list的模擬實現(xiàn)
- 默認(rèn)成員函數(shù)
- 構(gòu)造函數(shù)
- 拷貝構(gòu)造函數(shù)
- 賦值運算符重載
- 析構(gòu)函數(shù)
- 迭代器
- 迭代器為什么要存在?
- const_iterator
- begin和end
- insert
- erase
- push_back && pop_back
- push_front &&pop_front
- swap
- 完整代碼
list的模擬實現(xiàn)
默認(rèn)成員函數(shù)
構(gòu)造函數(shù)
list是一個帶頭雙向循環(huán)鏈表,在構(gòu)造一個list對象時,new一個頭結(jié)點,并讓其prev和next都指向自己即可。
void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}//默認(rèn)構(gòu)造list(){empty_init();}
拷貝構(gòu)造函數(shù)
//拷貝構(gòu)造函數(shù)
list(const list<T>& lt)
{_head = new node; //申請一個頭結(jié)點_head->_next = _head; //頭結(jié)點的后繼指針指向自己_head->_prev = _head; //頭結(jié)點的前驅(qū)指針指向自己for (auto & e : lt) //兩個 e都是同一個{push_back(e); //將容器lt當(dāng)中的數(shù)據(jù)一個個尾插到新構(gòu)造的容器后面}
}
賦值運算符重載
版本一(推薦):
參數(shù)不使用引用,讓編譯器自動調(diào)用list的拷貝構(gòu)造函數(shù)構(gòu)造出來一個list對象,然后調(diào)用swap函數(shù)將原容器與該list對象進行交換
這樣做相當(dāng)于將應(yīng)該用clear清理的數(shù)據(jù),通過交換函數(shù)交給了容器lt,而當(dāng)賦值運算符重載函數(shù)調(diào)用結(jié)束時,容器lt會自動銷毀,并調(diào)用其析構(gòu)函數(shù)進行清理。
list<T> & operator= (list<T> lt)//右值沒有引用傳參,間接調(diào)用拷貝構(gòu)造//list<T>& operator= ( list<T> * this, list<T> lt)//右值沒有引用傳參,間接調(diào)用拷貝構(gòu)造// lt1 = lt2{this->swap(lt);return *this; }
版本二:
先調(diào)用clear函數(shù)將原容器清空,然后將容器lt當(dāng)中的數(shù)據(jù),通過遍歷的方式一個個尾插到清空后的容器當(dāng)中即可。
list<T>& operator=(const list<T>& lt)
{if (this != <) //避免自己給自己賦值{clear(); //清空容器for (const auto& e : lt){push_back(e); //將容器lt當(dāng)中的數(shù)據(jù)一個個尾插到鏈表后面}}return *this; //支持連續(xù)賦值
}
析構(gòu)函數(shù)
對對象進行析構(gòu)時,首先調(diào)用clear函數(shù)清理容器當(dāng)中的數(shù)據(jù),然后將頭結(jié)點釋放,最后將頭指針置空
void clear(){iterator it = begin();while (it!= end() ) {it = erase(it);}_size = 0;}~list(){clear();delete _head;_head = nullptr;}
迭代器
迭代器為什么要存在?
string 和vector的迭代器
string和vector將數(shù)據(jù)存儲在一段連續(xù)的內(nèi)存空間,那么可以通過指針進行自增、自減以及解引用等操作,就可以對相應(yīng)位置的數(shù)據(jù)進行一系列操作,所以string和vector是天然的迭代器
list的迭代器
list中各個結(jié)點在內(nèi)存當(dāng)中的位置是隨機的,不一定是連續(xù)的,我們不能僅通過結(jié)點指針的自增、自減以及解引用等操作對相應(yīng)結(jié)點的數(shù)據(jù)進行操作 ,采用類封裝迭代器,在迭代器類的內(nèi)部,重載 ++ 、 --、 *、 -> 、 !=、 == 這些迭代器會用到的運算符
const_iterator
在const迭代器中,const迭代器指向的內(nèi)容不能被修改。也就是解引用返回的值不能被修改。迭代器本身是可以修改的,有兩種解決方案 :
1 再封裝一個const迭代器類
template< class T>//const 迭代器 ,讓迭代器指向的內(nèi)容不能修改, 迭代器本身可以修改struct __list_const_iterator{typedef list_node<T> Node;//構(gòu)造函數(shù)__list_const_iterator(Node* node):_node(node){}const T& operator*()//出了作用域,節(jié)點的值還在,用引用//const: 返回節(jié)點的值,不能修改{return _node->_val;}//前置++,返回++之后的值__list_const_iterator& operator++()//__list_const_iterator& operator++(__list_const_iterator * this ){_node = _node->_next;return *this;}//后置++ ,返回++之前的值__list_const_iterator operator++(int){__list_const_iterator tmp(*this);_node = _node->_next;return tmp;// tmp出了作用域就被銷毀 ,用傳值返回 }bool operator==(const __list_iterator<T>& it){return *this == it._node;}bool operator!=(const __list_iterator<T>& it)//傳值返回,返回的是拷貝,是一個臨時對象,臨時對象具有常性{return *this != it._node;}Node* _node;};
2 選擇增加模板參數(shù),復(fù)用代碼(推薦)
template<class T, class Ref, class Ptr>
c++庫就是用的這種解決方案
//template<class T> //list類存儲的數(shù)據(jù)是任意類型,所以需要設(shè)置模板參數(shù)//普通迭代器//Ref是引用 ,Ptr是指針template<class T,class Ref,class Ptr>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self;//構(gòu)造函數(shù)__list_iterator(Node* node):_node(node){}Ref operator*(){return _node->_val;}Ptr operator->(){return &_node->_val;}//前置++,返回++之后的值self & operator++()//__list_iterator<T> & operator++(__list_iterator<T> * this ){_node = _node->_next;return *this;}//后置++ ,返回++之前的值self operator++(int)// __list_iterator<T> operator++( __list_iterator<T> * this ,int){self tmp(*this);//拷貝構(gòu)造_node = _node->_next;return tmp; // tmp出了作用域就被銷毀 ,用傳值返回 }bool operator!= (const self& it){return _node != it._node;}bool operator== (const self & it){return _node == it._node;}Node* _node;};template<class T>//list類存儲的數(shù)據(jù)是任意類型,所以需要設(shè)置模板參數(shù)class list{typedef list_node<T> Node;public:typedef __list_iterator<T ,T&,T* > iterator;typedef __list_iterator<T, const T&, const T * > const_iterator;//迭代器 //能直接顯示構(gòu)造最好顯式構(gòu)造,不要把決定權(quán)給編譯器進行單參數(shù)的隱式類型轉(zhuǎn)換iterator end() //最后一個數(shù)據(jù)的下一個位置,即頭節(jié)點{//return _head; // _head的類型是list_node<T>* ,iterator的類型是__list_iterator<T> ,類型不一致,涉及到單參數(shù)的構(gòu)造函數(shù)支持隱式類型轉(zhuǎn)換 //還可以寫成 return iterator(_head);return iterator(_head);}iterator begin()//第一個數(shù)據(jù)的位置,即頭節(jié)點的下一個位置{//return _head->_next;//單參數(shù)的構(gòu)造函數(shù)支持隱式類型轉(zhuǎn)換//還可以寫成 return iterator(_head->_next)return iterator(_head->_next);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}//默認(rèn)構(gòu)造list(){empty_init();}// lt2(lt1)//還沒有實現(xiàn)const_iteratorlist(const list<T>& lt){empty_init();//拷貝數(shù)據(jù)for (auto & e :lt )//遍歷lt{push_back(e);}}~list(){clear();delete _head;_head = nullptr;}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}void swap(list<T> & lt){std:: swap(_head,lt._head );std::swap(_size, lt._size);}list<T> & operator= (list<T> lt)//右值沒有引用傳參,間接調(diào)用拷貝構(gòu)造//list<T>& operator= ( list<T> * this, list<T> lt)//右值沒有引用傳參,間接調(diào)用拷貝構(gòu)造// lt1 = lt2{this->swap(lt);return *this; }void clear(){iterator it = begin();while (it!= end() ) {it = erase(it);}_size = 0;}void push_back(const T& x){insert(end(), x);//在最后一個數(shù)據(jù)的下一個位置插入}//pos位置之前插入iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);// prev newnode cur 鏈接關(guān)系prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;return newnode;}iterator erase (iterator pos){assert(pos != end());Node* cur = pos._node;Node* next = cur->_next;Node* prev = cur->_prev;//prev next prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}size_t size(){return _size;}void push_front( const T & x )//T可能是vector ,用引用,減少拷貝{insert(begin(),x);}void pop_back(){erase(--end());//end是最后一個數(shù)據(jù)的下一個位置,需要--,到達(dá)最后一個數(shù)據(jù),這樣才是尾刪}void pop_front(){erase(begin());}private:Node* _head;size_t _size;};
當(dāng)我們定義const對象時,會自動調(diào)用const修飾的迭代器。當(dāng)調(diào)用const修飾的迭代器時,__list_iterator的模板參數(shù)就會實例化為const T&。實際上在實例化時,const和非const修飾的還是兩個不同類,只不過是實例化的代碼工作交給了編譯器處理了。
begin和end
對于list,第一個有效數(shù)據(jù)的迭代器就是頭結(jié)點后一個結(jié)點
begin函數(shù)返回的是第一個有效數(shù)據(jù)的迭代器,即頭節(jié)點的下一個位置
end函數(shù)返回的是最后一個有效數(shù)據(jù)的下一個位置的迭代器,即頭節(jié)點
iterator end() //最后一個數(shù)據(jù)的下一個位置,即頭節(jié)點{return _head; // _head的類型是list_node<T>* ,iterator的類型是__list_iterator<T> ,類型不一致,涉及到單參數(shù)的構(gòu)造函數(shù)支持隱式類型轉(zhuǎn)換 //還可以寫成 return iterator(_head);}iterator begin()//第一個數(shù)據(jù)的位置,即頭節(jié)點的下一個位置{return _head->_next;//單參數(shù)的構(gòu)造函數(shù)支持隱式類型轉(zhuǎn)換//還可以寫成 return iterator(_head->_next)}
const對象的begin函數(shù)和end函數(shù)
const_iterator begin() const{return const_iterator(_head->_next);//返回使用頭結(jié)點后一個結(jié)點}const_iterator end() const{return const_iterator(_head);//返回使用頭結(jié)點}
insert
重新改變prev newnode cur 三者之間的鏈接關(guān)系
//pos位置之前插入iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);// prev newnode cur 鏈接關(guān)系prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;return newnode;}
erase
改變prev和next之間的鏈接關(guān)系,然后釋放cur
iterator erase (iterator pos){assert(pos != end());Node* cur = pos._node;Node* next = cur->_next;Node* prev = cur->_prev;//prev next prev->_next = next;next->_prev = prev;delete cur ;--_size;return next;}
push_back && pop_back
void push_back(const T& x){insert(end(), x);//在最后一個數(shù)據(jù)的下一個位置插入}void pop_back(){erase(--end());//end是最后一個數(shù)據(jù)的下一個位置,需要--,到達(dá)最后一個數(shù)據(jù),這樣才是尾刪}
push_front &&pop_front
void pop_front(){erase(begin());}void push_front( const T & x )//T可能是vector ,用引用,減少拷貝{insert(begin(),x);}
swap
swap函數(shù)用于交換兩個容器,list容器當(dāng)中存儲的是鏈表的頭指針和size,我們將這兩個容器當(dāng)中的頭指針和size交換
void swap(list<T> & lt){std:: swap(_head,lt._head );std::swap(_size, lt._size);}
注意: 這里調(diào)用庫里的swap模板函數(shù),需要在swap函數(shù)之前加上“std::”,告訴編譯器在c++標(biāo)準(zhǔn)庫尋找swap函數(shù),否則編譯器編譯時會認(rèn)為你調(diào)用的是正在實現(xiàn)的swap函數(shù)(就近原則)
總結(jié)
完整代碼
#pragma once
#include<iostream>
#include<assert.h>
#include<list>
using namespace std;
namespace cxq
{//list類存儲的數(shù)據(jù)是任意類型,所以需要設(shè)置模板參數(shù)template<class T>//節(jié)點struct list_node{//構(gòu)造函數(shù)list_node(const T& val = T()) //缺省值是匿名對象,c++對內(nèi)置類型進行了升級:_prev(nullptr), _next(nullptr), _val(val){}list_node<T>* _prev;list_node<T>* _next;T _val;};//template<class T> //list類存儲的數(shù)據(jù)是任意類型,所以需要設(shè)置模板參數(shù)//普通迭代器//Ref是引用 ,Ptr是指針template<class T,class Ref,class Ptr>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self;//構(gòu)造函數(shù)__list_iterator(Node* node):_node(node){}Ref operator*(){return _node->_val;}Ptr operator->(){return &_node->_val;}//前置++,返回++之后的值self & operator++()//__list_iterator<T> & operator++(__list_iterator<T> * this ){_node = _node->_next;return *this;}//后置++ ,返回++之前的值self operator++(int)// __list_iterator<T> operator++( __list_iterator<T> * this ,int){self tmp(*this);//拷貝構(gòu)造_node = _node->_next;return tmp; // tmp出了作用域就被銷毀 ,用傳值返回 }bool operator!= (const self& it){return _node != it._node;}bool operator== (const self & it){return _node == it._node;}Node* _node;};//template< class T>const 迭代器 ,讓迭代器指向的內(nèi)容不能修改, 迭代器本身可以修改//struct __list_const_iterator//{// typedef list_node<T> Node;// //構(gòu)造函數(shù)// __list_const_iterator(Node* node)// :_node(node)// {// }// const T& operator*()//出了作用域,節(jié)點的值還在,用引用// //const: 返回節(jié)點的值,不能修改// {// return _node->_val;// }// //前置++,返回++之后的值// __list_const_iterator& operator++()// //__list_const_iterator& operator++(__list_const_iterator * this )// {// _node = _node->_next;// return *this;// }// //后置++ ,返回++之前的值// __list_const_iterator operator++(int)// {// __list_const_iterator tmp(*this);// _node = _node->_next;// return tmp;// tmp出了作用域就被銷毀 ,用傳值返回 // }// bool operator==(const __list_iterator<T>& it)// {// return *this == it._node;// }// bool operator!=(const __list_iterator<T>& it)//傳值返回,返回的是拷貝,是一個臨時對象,臨時對象具有常性// {// return *this != it._node;// }// Node* _node;//};template<class T>//list類存儲的數(shù)據(jù)是任意類型,所以需要設(shè)置模板參數(shù)class list{typedef list_node<T> Node;public:typedef __list_iterator<T ,T&,T* > iterator;//普通迭代器typedef __list_iterator<T, const T&, const T * > const_iterator;//const 迭代器//迭代器 //能直接顯示構(gòu)造最好顯式構(gòu)造,不要把決定權(quán)給編譯器進行單參數(shù)的隱式類型轉(zhuǎn)換iterator end() //最后一個數(shù)據(jù)的下一個位置,即頭節(jié)點{//return _head; // _head的類型是list_node<T>* ,iterator的類型是__list_iterator<T> ,類型不一致,涉及到單參數(shù)的構(gòu)造函數(shù)支持隱式類型轉(zhuǎn)換 //還可以寫成 return iterator(_head);return iterator(_head);}iterator begin()//第一個數(shù)據(jù)的位置,即頭節(jié)點的下一個位置{//return _head->_next;//單參數(shù)的構(gòu)造函數(shù)支持隱式類型轉(zhuǎn)換//還可以寫成 return iterator(_head->_next)return iterator(_head->_next);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}//默認(rèn)構(gòu)造list(){empty_init();}// lt2(lt1)//還沒有實現(xiàn)const_iteratorlist(const list<T>& lt){empty_init();//拷貝數(shù)據(jù)for (auto & e :lt )//遍歷lt{push_back(e);}}~list(){clear();delete _head;_head = nullptr;}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}void swap(list<T> & lt){std:: swap(_head,lt._head );std::swap(_size, lt._size);}list<T> & operator= (list<T> lt)//右值沒有引用傳參,間接調(diào)用拷貝構(gòu)造//list<T>& operator= ( list<T> * this, list<T> lt)//右值沒有引用傳參,間接調(diào)用拷貝構(gòu)造// lt1 = lt2{this->swap(lt);return *this; }void clear(){iterator it = begin();while (it!= end() ) {it = erase(it);}_size = 0;}void push_back(const T& x){找尾//Node* tail = _head->_prev;//Node* newnode = new Node(x);改變鏈接關(guān)系 ///*newnode = tail->next;*///tail->_next = newnode;//newnode->_prev = tail;//_head->_prev = newnode;//newnode->_next = _head;insert(end(), x);//在最后一個數(shù)據(jù)的下一個位置插入}//pos位置之前插入iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);// prev newnode cur 鏈接關(guān)系prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;return newnode;}iterator erase (iterator pos){assert(pos != end());Node* cur = pos._node;Node* next = cur->_next;Node* prev = cur->_prev;//prev next prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}size_t size(){return _size;}void push_front( const T & x )//T可能是vector ,用引用,減少拷貝{insert(begin(),x);}void pop_back(){erase(--end());//end是最后一個數(shù)據(jù)的下一個位置,需要--,到達(dá)最后一個數(shù)據(jù),這樣才是尾刪}void pop_front(){erase(begin());}private:Node* _head;size_t _size;};void test_list1(){list<int> lt1;lt1.push_back(1);lt1.push_back(2);list<int>::iterator it = lt1.begin();//拷貝構(gòu)造while (it != lt1.end()){cout << *it << " ";it++;}cout << endl;}void test_list2(){list<int> lt1;lt1.push_back(1);lt1.push_back(2);list<int> lt2 (lt1);for (auto e : lt1){cout << e << " ";}cout << endl;}
}
如果你覺得這篇文章對你有幫助,不妨動動手指給點贊收藏加轉(zhuǎn)發(fā),給鄃鱈一個大大的關(guān)注你們的每一次支持都將轉(zhuǎn)化為我前進的動力!!!