南昌網(wǎng)站建設(shè)方案報(bào)價(jià)企業(yè)培訓(xùn)公司
目錄
1. list的介紹及使用
1.1 list的介紹
1.2 list的使用
1.2.1 list的構(gòu)造
1.2.2 list iterator的使用
?1.2.3 list capacity
1.2.4 list element access
?1.2.5 list modififiers
1.2.6 list的迭代器失效
2. list的模擬實(shí)現(xiàn)
2.1 模擬實(shí)現(xiàn)list
2.2 list的反向迭代器
1. list的介紹及使用
1.1 list的介紹
1. list 是可以在常數(shù)范圍內(nèi)在任意位置進(jìn)行插入和刪除的序列式容器,并且該容器可以前后雙向迭代。
2. list 的底層是雙向鏈表結(jié)構(gòu),雙向鏈表中每個(gè)元素存儲(chǔ)在互不相關(guān)的獨(dú)立節(jié)點(diǎn)中,在節(jié)點(diǎn)中通過指針指向其前一個(gè)元素和后一個(gè)元素。
3. list 與 forward_list 非常相似:最主要的不同在于 forward_list 是單鏈表,只能朝前迭代,已讓其更簡單高效。
4. 與其他的序列式容器相比 (array , vector , deque) , list 通常在任意位置進(jìn)行插入、移除元素的執(zhí)行效率更好。
5. 與其他序列式容器相比, list 和 forward_list 最大的缺陷是不支持任意位置的隨機(jī)訪問,比如:要訪問 list的第6 個(gè)元素,必須從已知的位置 ( 比如頭部或者尾部 ) 迭代到該位置,在這段位置上迭代需要線性的時(shí)間開銷;list 還需要一些額外的空間,以保存每個(gè)節(jié)點(diǎn)的相關(guān)聯(lián)信息 ( 對(duì)于存儲(chǔ)類型較小元素的大 list 來說這可能是一個(gè)重要的因素)

?
1.2 list的使用
list 中的接口比較多,此處類似,只需要掌握如何正確的使用,然后再去深入研究背后的原理,已達(dá)到可擴(kuò)展的能力。以下為list 中一些 常見的重要接口
1.2.1 list的構(gòu)造
構(gòu)造函數(shù)((constructor) )接口說明list (size_type n, const value_type& val = value_type())構(gòu)造的 list 中包含 n 個(gè)值為 val 的元素list()構(gòu)造空的 listlist (const list& x)拷貝構(gòu)造函數(shù)list (InputIterator fifirst, InputIterator last)用 [fifirst, last) 區(qū)間中的元素構(gòu)造 list
1.2.2 list iterator的使用
此處,大家可暫時(shí) 將迭代器理解成一個(gè)指針,該指針指向 list 中的某個(gè)節(jié)點(diǎn) 。
?
?
【注意】
1. begin 與 end 為正向迭代器,對(duì)迭代器執(zhí)行 ++ 操作,迭代器向后移動(dòng)
2. rbegin(end) 與 rend(begin) 為反向迭代器,對(duì)迭代器執(zhí)行 ++ 操作,迭代器向前移動(dòng)
?1.2.3 list capacity
1.2.4 list element access
?
?1.2.5 list modififiers
函數(shù)聲明接口說明push_front在 list 首元素前插入值為 val 的元素pop_front刪除 list 中第一個(gè)元素push_back在 list 尾部插入值為 val 的元素pop_back刪除 list 中最后一個(gè)元素insert在 list position 位置中插入值為 val 的元素erase刪除 list position 位置的元素swap交換兩個(gè) list 中的元素clear清空 list 中的有效元素
1.2.6 list的迭代器失效
前面說過,此處大家可將迭代器暫時(shí)理解成類似于指針, 迭代器失效即迭代器所指向的節(jié)點(diǎn)的無效,即該節(jié) 點(diǎn)被刪除了 。因?yàn)?/span> list 的底層結(jié)構(gòu)為帶頭結(jié)點(diǎn)的雙向循環(huán)鏈表 ,因此 在 list 中進(jìn)行插入時(shí)是不會(huì)導(dǎo)致 list 的迭代 器失效的,只有在刪除時(shí)才會(huì)失效,并且失效的只是指向被刪除節(jié)點(diǎn)的迭代器,其他迭代器不會(huì)受到影響 。
2. list的模擬實(shí)現(xiàn)
2.1 模擬實(shí)現(xiàn)list
要模擬實(shí)現(xiàn) list ,必須要熟悉 list 的底層結(jié)構(gòu)以及其接口的含義,通過上面的學(xué)習(xí),這些內(nèi)容已基本掌握,現(xiàn)在我們來模擬實(shí)現(xiàn)list 。
#pragma once#include <iostream>
using namespace std;
#include <assert.h>namespace bite
{// List的節(jié)點(diǎn)類template<class T>struct ListNode{ListNode(const T& val = T()): _prev(nullptr), _next(nullptr), _val(val){}ListNode<T>* _prev;ListNode<T>* _next;T _val;};/*List 的迭代器迭代器有兩種實(shí)現(xiàn)方式,具體應(yīng)根據(jù)容器底層數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn):1. 原生態(tài)指針,比如:vector2. 將原生態(tài)指針進(jìn)行封裝,因迭代器使用形式與指針完全相同,因此在自定義的類中必須實(shí)現(xiàn)以下方法:1. 指針可以解引用,迭代器的類中必須重載operator*()2. 指針可以通過->訪問其所指空間成員,迭代器類中必須重載oprator->()3. 指針可以++向后移動(dòng),迭代器類中必須重載operator++()與operator++(int)至于operator--()/operator--(int)釋放需要重載,根據(jù)具體的結(jié)構(gòu)來抉擇,雙向鏈表可以向前 移動(dòng),所以需要重載,如果是forward_list就不需要重載--4. 迭代器需要進(jìn)行是否相等的比較,因此還需要重載operator==()與operator!=()*/template<class T, class Ref, class Ptr>class ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;// Ref 和 Ptr 類型需要重定義下,實(shí)現(xiàn)反向迭代器時(shí)需要用到public:typedef Ref Ref;typedef Ptr Ptr;public://// 構(gòu)造ListIterator(Node* node = nullptr): _node(node){}//// 具有指針類似行為Ref operator*() { return _node->_val;}Ptr operator->() { return &(operator*()); }//// 迭代器支持移動(dòng)Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self temp(*this);_node = _node->_next;return temp;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self temp(*this);_node = _node->_prev;return temp;}//// 迭代器支持比較bool operator!=(const Self& l)const{ return _node != l._node;}bool operator==(const Self& l)const{ return _node != l._node;}Node* _node;};template<class Iterator>class ReverseListIterator{// 注意:此處typename的作用是明確告訴編譯器,Ref是Iterator類中的一個(gè)類型,而不是靜態(tài)成員變量// 否則編譯器編譯時(shí)就不知道Ref是Iterator中的類型還是靜態(tài)成員變量// 因?yàn)殪o態(tài)成員變量也是按照 類名::靜態(tài)成員變量名 的方式訪問的public:typedef typename Iterator::Ref Ref;typedef typename Iterator::Ptr Ptr;typedef ReverseListIterator<Iterator> Self;public://// 構(gòu)造ReverseListIterator(Iterator it): _it(it){}//// 具有指針類似行為Ref operator*(){Iterator temp(_it);--temp;return *temp;}Ptr operator->(){return &(operator*());}//// 迭代器支持移動(dòng)Self& operator++(){--_it;return *this;}Self operator++(int){Self temp(*this);--_it;return temp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self temp(*this);++_it;return temp;}//// 迭代器支持比較bool operator!=(const Self& l)const{return _it != l._it;}bool operator==(const Self& l)const{return _it != l._it;}Iterator _it;};template<class T>class list{typedef ListNode<T> Node;public:// 正向迭代器typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;// 反向迭代器typedef ReverseListIterator<iterator> reverse_iterator;typedef ReverseListIterator<const_iterator> const_reverse_iterator;public:///// List的構(gòu)造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中的元素構(gòu)造臨時(shí)的temp,然后與當(dāng)前對(duì)象交換list<T> temp(l.begin(), l.end());this->swap(temp);}list<T>& operator=(list<T> l){this->swap(l);return *this;}~list(){clear();delete _head;_head = nullptr;}///// List的迭代器iterator begin() { return iterator(_head->_next); }iterator end() { return iterator(_head); }const_iterator begin()const { return const_iterator(_head->_next); }const_iterator end()const{ return const_iterator(_head); }reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}const_reverse_iterator rend()const{return const_reverse_iterator(begin());}///// List的容量相關(guān)size_t size()const{Node* cur = _head->_next;size_t count = 0;while (cur != _head){count++;cur = cur->_next;}return count;}bool empty()const{return _head->_next == _head;}void resize(size_t newsize, const T& data = T()){size_t oldsize = size();if (newsize <= oldsize){// 有效元素個(gè)數(shù)減少到newsizewhile (newsize < oldsize){pop_back();oldsize--;}}else{while (oldsize < newsize){push_back(data);oldsize++;}}}// List的元素訪問操作// 注意:List不支持operator[]T& front(){return _head->_next->_val;}const T& front()const{return _head->_next->_val;}T& back(){return _head->_prev->_val;}const T& back()const{return _head->_prev->_val;}// List的插入和刪除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()); }// 在pos位置前插入值為val的節(jié)點(diǎn)iterator insert(iterator pos, const T& val){Node* pNewNode = new Node(val);Node* pCur = pos._node;// 先將新節(jié)點(diǎn)插入pNewNode->_prev = pCur->_prev;pNewNode->_next = pCur;pNewNode->_prev->_next = pNewNode;pCur->_prev = pNewNode;return iterator(pNewNode);}// 刪除pos位置的節(jié)點(diǎn),返回該節(jié)點(diǎn)的下一個(gè)位置iterator erase(iterator pos){// 找到待刪除的節(jié)點(diǎn)Node* pDel = pos._node;Node* pRet = pDel->_next;// 將該節(jié)點(diǎn)從鏈表中拆下來并刪除pDel->_prev->_next = pDel->_next;pDel->_next->_prev = pDel->_prev;delete pDel;return iterator(pRet);}void clear(){Node* cur = _head->_next;// 采用頭刪除刪除while (cur != _head){_head->_next = cur->_next;delete cur;cur = _head->_next;}_head->_next = _head->_prev = _head;}void swap(bite::list<T>& l){std::swap(_head, l._head);}private:void CreateHead(){_head = new Node;_head->_prev = _head;_head->_next = _head;}private:Node* _head;};
}///
// 對(duì)模擬實(shí)現(xiàn)的list進(jìn)行測試
// 正向打印鏈表
template<class T>
void PrintList(const bite::list<T>& l)
{auto it = l.begin();while (it != l.end()){cout << *it << " ";++it;}cout << endl;
}// 測試List的構(gòu)造
void TestBiteList1()
{bite::list<int> l1;bite::list<int> l2(10, 5);PrintList(l2);int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };bite::list<int> l3(array, array + sizeof(array) / sizeof(array[0]));PrintList(l3);bite::list<int> l4(l3);PrintList(l4);l1 = l4;PrintList(l1);
}// PushBack()/PopBack()/PushFront()/PopFront()
void TestBiteList2()
{// 測試PushBack與PopBackbite::list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);PrintList(l);l.pop_back();l.pop_back();PrintList(l);l.pop_back();cout << l.size() << endl;// 測試PushFront與PopFrontl.push_front(1);l.push_front(2);l.push_front(3);PrintList(l);l.pop_front();l.pop_front();PrintList(l);l.pop_front();cout << l.size() << endl;
}// 測試insert和erase
void TestBiteList3()
{int array[] = { 1, 2, 3, 4, 5 };bite::list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto pos = l.begin();l.insert(l.begin(), 0);PrintList(l);++pos;l.insert(pos, 2);PrintList(l);l.erase(l.begin());l.erase(pos);PrintList(l);// pos指向的節(jié)點(diǎn)已經(jīng)被刪除,pos迭代器失效cout << *pos << endl;auto it = l.begin();while (it != l.end()){it = l.erase(it);}cout << l.size() << endl;
}// 測試反向迭代器
void TestBiteList4()
{int array[] = { 1, 2, 3, 4, 5 };bite::list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto rit = l.rbegin();while (rit != l.rend()){cout << *rit << " ";++rit;}cout << endl;const bite::list<int> cl(l);auto crit = l.rbegin();while (crit != l.rend()){cout << *crit << " ";++crit;}cout << endl;
}
2.2 list的反向迭代器
通過前面例子知道,反向迭代器的 ++ 就是正向迭代器的 -- ,反向迭代器的 -- 就是正向迭代器的 ++ ,因此反向迭代器的實(shí)現(xiàn)可以借助正向迭代器,即:反向迭代器內(nèi)部可以包含一個(gè)正向迭代器,對(duì)正向迭代器的接口進(jìn)行包裝即可。
template<class Iterator>
class ReverseListIterator
{// 注意:此處typename的作用是明確告訴編譯器,Ref是Iterator類中的類型,而不是靜態(tài)成員變量// 否則編譯器編譯時(shí)就不知道Ref是Iterator中的類型還是靜態(tài)成員變量// 因?yàn)殪o態(tài)成員變量也是按照 類名::靜態(tài)成員變量名 的方式訪問的
public:typedef typename Iterator::Ref Ref;typedef typename Iterator::Ptr Ptr;typedef ReverseListIterator<Iterator> Self;
public://// 構(gòu)造ReverseListIterator(Iterator it): _it(it){}//// 具有指針類似行為Ref operator*(){Iterator temp(_it);--temp;return *temp;}Ptr operator->(){ return &(operator*());}//// 迭代器支持移動(dòng)Self& operator++(){
--_it;return *this;}Self operator++(int){Self temp(*this);--_it;return temp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self temp(*this);++_it;return temp;}//// 迭代器支持比較bool operator!=(const Self& l)const{ return _it != l._it;}bool operator==(const Self& l)const{ return _it != l._it;}Iterator _it;
};