? ? ? ? 在上一篇學習了list的使用后,在本篇我們將通過模擬實現的方式深入了解list的底層運作原理。
? ? ? ? 作者的個人gitee:樓田莉子 (riko-lou-tian) - Gitee.com
? ? ? ? 感興趣的讀者可以看一看
目錄
前置準備
? ? ? ? 結點的定義
????????鏈表類的定義
迭代器?
????????普通迭代器
????????const迭代器?
? ? ? ? list中關于迭代器的聲明?
? ? ? ? 誤區:
相關函數
????????push_back
? ? ? ? insert
? ? ? ? erase
源代碼
前置準備
? ? ? ? 結點的定義
? ? ? ? 我們需要定義一個結點的類(參考之前雙向鏈表那篇博客:數據結構學習之雙向循環鏈表-CSDN博客),因為這個類中的成員我們都想要訪問,如果想要方便寫的話,可以用struct(struct中默認為公開),并且用命名空間封裝
namespace Boogiepop
{template<class T>//當我們不需要也不想要讓訪問限定符限制的時候//可以用struct來定義類,而不是用classstruct list_node{T _data; //數據list_node<T>* _next;//指向下一個節點的指針list_node<T>* _prev;//指向前一個節點的指針};
}
? ? ? ? 同時因為list模擬實現中使用了模板,所以函數的定義也只能在.h文件中()?
? ? ? ? 同時切記,模板只能給對應的類或函數使用,是“一次性”的,想再次使用一樣的模板必須重新定義
????????鏈表類的定義
template<class T>
class list
{typedef list_node<T> node;
public://構造函數list(){_head = new node;_head->_next = _head;_head->_prev = _head;}
private:node* _head; //指向頭節點的指針};
迭代器?
????????雙鏈表迭代器相關圖解:
?????????迭代器用node*封裝無法達到預期行為;用類封裝node*重載運算符,就可以控制迭代器的行為。
? ? ? ? 迭代器行為模擬的是普通指針訪問數組的行為
????????普通迭代器
//迭代器template<class T,class Ref>//當我們不需要也不想要讓訪問限定符限制的時候//可以用struct來定義類,而不是用class//普通迭代器struct _list_iterator{typedef list_node<T> node;typedef _list_iterator<T, Ref> Self;node* _node;//構造迭代器_list_iterator(node* node) :_node(node){}//解引用不是結點//用引用返回可以修改這個數值T& operator*(){return _node->_data;}////不能實現,因為const list_iterator對象才能調用這個重載////但是在這種情況下const list_iterator對象不能調用++和--//const T& operator*()const//{// return _node->_data;//}//迭代器++//前置++Self& operator++(){_node = _node->_next;return *this;}//后置Self& operator++(int){_list_iterator<T,Ref> tmp (*this);//淺拷貝_node = _node->_next;return *this;}//前置--Self& operator--(){_node = _node->prev;return *this;}//后置--Self& operator--(int){Self tmp (*this);//淺拷貝_node = _node->prev;return *this;}//返回是否相等bool operator!=(const Self& it)const{return _node!= it._node; }bool operator==(const Self& it)const{return _node == it._node;}};
????????const迭代器?
//const迭代器template<class T,class Ref>//當我們不需要也不想要讓訪問限定符限制的時候//可以用struct來定義類,而不是用classstruct _list_const_iterator{typedef list_node<T> node;typedef _list_const_iterator<T, Ref> Self;node* _node;//構造迭代器_list_const_iterator(node* node) :_node(node){}//解引用不是結點//用引用返回可以修改這個數值const Self& operator*(){return _node->_data;}//迭代器++//前置++Self& operator++(){_node = _node->_next;return *this;}//后置Self& operator++(int){Self tmp(*this);//淺拷貝_node = _node->_next;return *this;}//前置--Self& operator--(){_node = _node->prev;return *this;}//后置--Self& operator--(int){Self tmp(*this);//淺拷貝_node = _node->prev;return *this;}//返回是否相等bool operator!=(const Self& it)const{return _node != it._node;}bool operator==(const Self& it)const{return _node == it._node;}};
? ? ? ? list中關于迭代器的聲明?
//鏈表
template<class T>
class list
{typedef list_node<T> node;
public://普通迭代器typedef _list_iterator<T,Ref> iterator;//const迭代器typedef const _list_iterator<T,Ref> const_iterator;//返回迭代器iterator begin(){return iterator(_head->_next);}//返回迭代器iterator end(){return iterator(_head);}//其余部分在此處省略。。。。。。
}
?測試:
void test1()
{Boogiepop::list<int> list;list.push_back(1);list.push_back(2);list.push_back(3);list.push_back(4);list.push_back(5);Boogiepop::list<int>::iterator it = list.begin();while (it != list.end()){cout << *it << " ";++it;}cout<<endl;
}
? ? ? ? 普通迭代器可以修改指向的內容,const迭代器不可以修改指向的內容
? ? ? ? 誤區:
? ? ? ? 1、
? ? ? ? 這么寫是不對的,這樣迭代器本身無法修改,無法進行++和--
typedef const iterator const_iterator;
? ? ? ? string和vector可以這么干是因為const修飾的指向的內容?
? ? ? ? 但是list只能重新搞一個類型實現
?????????2、還有這種情況,寫重載能否實現?答案是不能
T& operator*()
{return _node->_data;
}
const T& operator*()const
{return _node->_data;
}
? ? ? ? 因為:
T& operator*()
{return _node->_data;
}
//不能實現,因為const list_iterator對象才能調用這個重載
//但是在這種情況下const list_iterator對象不能調用++和--
const T& operator*()const
{return _node->_data;
}
????????
相關函數
????????push_back
void push_back(const T&x)
{node* new_node = new node(x);//頭結點node* tail=_head->_prev;//尾節點tail->_next = new_node;new_node->_prev = tail;new_node->_next = _head;_head->_prev = new_node;
}
? ? ? ? insert
void insert(iterator pos, const T& x)
{node* cur = pos._node;node*new_node = new node(x);node*prev = cur->_prev;//prev new_node curprev->_next = new_node;new_node->_next = cur;cur->_prev = new_node;new_node->_prev = prev;
}
? ? ? ? erase
iterator erase(iterator pos)
{node* cur=pos._next;node*prev=cur->_prev;node*next=cur->_next;prev->_next=next;next->_prev=prev;delete cur;return iterator(next);//也可以這么寫return next
}
源代碼
list.h
#pragma once
#include<iostream>
using namespace std;
namespace Boogiepop
{//節點template<class T>//當我們不需要也不想要讓訪問限定符限制的時候//可以用struct來定義類,而不是用classstruct list_node{T _data; //數據list_node<T>* _next;//指向下一個節點的指針list_node<T>* _prev;//指向前一個節點的指針//構造函數list_node(const T& x = T()) :_data(x), _next(nullptr), _prev(nullptr){}};//迭代器template<class T, class Ref>//當我們不需要也不想要讓訪問限定符限制的時候//可以用struct來定義類,而不是用class//普通迭代器struct _list_iterator{typedef list_node<T> node;typedef _list_iterator<T, Ref> Self;node* _node;//構造迭代器_list_iterator(node* node) :_node(node){}//解引用不是結點//用引用返回可以修改這個數值T& operator*(){return _node->_data;}////不能實現,因為const list_iterator對象才能調用這個重載////但是在這種情況下const list_iterator對象不能調用++和--//const T& operator*()const//{// return _node->_data;//}//迭代器++//前置++Self& operator++(){_node = _node->_next;return *this;}//后置Self& operator++(int){_list_iterator<T, Ref> tmp(*this);//淺拷貝_node = _node->_next;return *this;}//前置--Self& operator--(){_node = _node->prev;return *this;}//后置--Self& operator--(int){Self tmp(*this);//淺拷貝_node = _node->prev;return *this;}//返回是否相等bool operator!=(const Self& it)const{return _node != it._node;}bool operator==(const Self& it)const{return _node == it._node;}};//const迭代器template<class T, class Ref>//當我們不需要也不想要讓訪問限定符限制的時候//可以用struct來定義類,而不是用class//普通迭代器struct _list_const_iterator{typedef list_node<T> node;typedef _list_const_iterator<T, Ref> Self;node* _node;//構造迭代器_list_const_iterator(node* node) :_node(node){}//解引用不是結點//用引用返回可以修改這個數值const Self& operator*(){return _node->_data;}//迭代器++//前置++Self& operator++(){_node = _node->_next;return *this;}//后置Self& operator++(int){Self tmp(*this);//淺拷貝_node = _node->_next;return *this;}//前置--Self& operator--(){_node = _node->prev;return *this;}//后置--Self& operator--(int){Self tmp(*this);//淺拷貝_node = _node->prev;return *this;}//返回是否相等bool operator!=(const Self& it)const{return _node != it._node;}bool operator==(const Self& it)const{return _node == it._node;}};//鏈表template<class T, class Ref>class list{typedef list_node<T> node;typedef _list_iterator<T, Ref> Self;typedef _list_const_iterator<T, Ref> const_Self;public://普通迭代器typedef _list_iterator<T, Ref> iterator;//const迭代器typedef const _list_iterator<T, Ref> const_iterator;//返回迭代器iterator begin(){return iterator(_head->_next);}//返回迭代器iterator end(){return iterator(_head);}//構造函數list(){_head = new node;_head->_next = _head;_head->_prev = _head;}//拷貝構造函數list(const list<T>& lt){_head = new node;_head->_next = _head;_head->_prev = _head;for (const auto& x : lt){push_back(x);}}//花括號初始化list(initializer_list<T> il){_head = new node;_head->_next = _head;_head->_prev = _head;for (const auto& x : lt){push_back(x);}}//=運算符重載list<T>& operator=(const list<T>& lt){if (this != <){clear();for (const auto& x : lt){push_back(x);}}return *this;}//析構函數//釋放結點~list(){clear();delete _head;_head = nullptr;}void push_back(const T& x){node* new_node = new node(x);//頭結點node* tail = _head->_prev;//尾節點tail->_next = new_node;new_node->_prev = tail;new_node->_next = _head;_head->_prev = new_node;}//交換數據void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}//插入元素void insert(iterator pos, const T& x){node* cur = pos._node;node* new_node = new node(x);node* prev = cur->_prev;//prev new_node curprev->_next = new_node;new_node->_next = cur;cur->_prev = new_node;new_node->_prev = prev;}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_front(){erase(begin());}void pop_back(){erase(--end());}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}iterator erase(iterator pos){node* cur = pos._next;node* prev = cur->_prev;node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;return iterator(next);//也可以這么寫return next}//返回鏈表大小size_t size()const{}private:node* _head; //指向頭節點的指針};
};
? ? ? ?
????????提示:類的模板沒有實例化不能去類模板中找后面的東西編譯器無法區分const_iterator 是嵌套內類還是靜態成員變量,typename是告訴編譯器確認過是類型
????????本期內容就到這里,感興趣的可以點個贊謝謝
封面圖自取:?