摘要:本文介紹了的常用接口的使用,并對其進(jìn)行了模擬實現(xiàn),包括迭代器的實現(xiàn)。與為反向迭代器,對迭代器執(zhí)行操作,迭代器向前移動。
本文介紹了list的常用接口的使用,并對其進(jìn)行了模擬實現(xiàn),包括list迭代器的實現(xiàn)。
目錄
list 容器,又稱雙向鏈表容器,即該容器的底層是以雙向鏈表的形式實現(xiàn)的。這意味著,list 容器中的元素可以分散存儲在內(nèi)存空間里,而不是必須存儲在一整塊連續(xù)的內(nèi)存空間中。結(jié)構(gòu)如圖。
?list是可以在常數(shù)范圍內(nèi)在任意位置進(jìn)行插入和刪除的序列式容器,并且該容器可以前后雙向迭代。
list與forward_list非常相似:最主要的不同在于forward_list是單鏈表,只能朝前迭代,已讓其更簡單高效。
?與其他的序列式容器相比(array,vector,deque),list通常在任意位置進(jìn)行插入、移除元素的執(zhí)行效率更好。最大的缺陷是不支持任意位置的隨機訪問,必須從已知的位置(比如頭部或者尾部)迭代到該位置,在這段位置上迭代需要線性的時間;list還需要一些額外的空間,以保存每個節(jié)點的相關(guān)聯(lián)信息。
構(gòu)造函數(shù)( (constructor)) | 接口說明 |
---|---|
list() | 構(gòu)造空的list |
list (size_type n, const value_type& val = value_type()) | 構(gòu)造的list中包含n個值為val的元素 |
list (const list& x) | 拷貝構(gòu)造函數(shù) |
list (InputIterator first, InputIterator last) | 用[first, last)區(qū)間中的元素構(gòu)造list |
#include #include int main (){ std::list a; // 構(gòu)造空的a std::list b (4,1); // b中放4個值為100的元素 std::list c (b.begin(), b.end()); // 用b的[begin(), end())左閉右開的區(qū)間構(gòu)造c std::list d (c); // 用c拷貝構(gòu)造d // 以數(shù)組為迭代器區(qū)間構(gòu)造e int array[] = {16,2,77,29}; std::list e (array, array + sizeof(array) / sizeof(int) ); // 用迭代器方式打印e中的元素 for(std::list::iterator it = e.begin(); it != e.end(); it++) std::cout << *it << " "; std::cout<
函數(shù)聲明 | 接口說明 |
---|---|
begin + end | 返回第一個元素的迭代器+返回最后一個元素下一個位置的迭代器 |
rbegin + rend | 返回第一個元素的reverse_iterator,即end位置,返回最后一個元素下一個位置的reverse_iterator,即begin位置 |
begin與end為正向迭代器,對迭代器執(zhí)行++操作,迭代器向后移動。
rbegin(end)與rend(begin)為反向迭代器,對迭代器執(zhí)行++操作,迭代器向前移動。
?
#include using namespace std;#include void print_list(const list& l){ // 注意這里調(diào)用的是list的 begin() const,返回list的const_iterator對象 for (list::const_iterator it = l.begin(); it != l.end(); ++it) { cout << *it << " "; // *it = 10; 編譯不通過 } cout << endl;}int main(){ int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; list l(array, array + sizeof(array) / sizeof(array[0])); // 使用正向迭代器正向list中的元素 for (list::iterator it = l.begin(); it != l.end(); ++it) cout << *it << " "; cout << endl; // 使用反向迭代器逆向打印list中的元素 for (list::reverse_iterator it = l.rbegin(); it != l.rend(); ++it) cout << *it << " "; cout << endl; return 0;}
函數(shù)聲明 | 接口說明 |
---|---|
empty | 檢測list是否為空,是返回true,否則返回false |
size | 返回list中有效節(jié)點的個數(shù) |
函數(shù)聲明 | 接口說明 |
---|---|
front | 返回list的第一個節(jié)點中值的引用 |
back | 返回list的最后一個節(jié)點中值的引用 |
函數(shù)聲明 | 接口說明 |
---|---|
push_front | 在list首元素前插入值為val的元素 |
pop_front | 刪除list中第一個元素 |
push_back | 在list尾部插入值為val的元素 |
pop_back | 刪除list中最后一個元素 |
insert | 在list position 位置中插入值為val的元素 |
erase | 刪除list position位置的元素 |
swap | 交換兩個list中的元素 |
clear | 清空list中的有效元素 |
此處可將迭代器暫時理解成類似于指針,迭代器失效即迭代器所指向的節(jié)點的無效,即該節(jié)點被刪除了。因為list的底層結(jié)構(gòu)為帶頭結(jié)點的雙向循環(huán)鏈表,因此在list中進(jìn)行插入時是不會導(dǎo)致list的迭代器失效的,只有在刪除時才會失效,并且失效的只是指向被刪除節(jié)點的迭代器,其他迭代器不會受到影響。
vector | list | |
---|---|---|
底 層 結(jié) 構(gòu) | 動態(tài)順序表,一段連續(xù)空間 | 帶頭結(jié)點的雙向循環(huán)鏈表 |
隨 機 訪 問 | 支持隨機訪問,訪問某個元素效率O(1) | 不支持隨機訪問,訪問某個元素效率O(N) |
插 入 和 刪 除 | 任意位置插入和刪除效率低,需要搬移元素,時間復(fù)雜度為O(N),插入時有可能需要增容,增容:開辟新空間,拷貝元素,釋放舊空間,導(dǎo)致效率更低 | |
空 間 利 用 率 | 底層為連續(xù)空間,不容易造成內(nèi)存碎片,空間利用率高,緩存利用率高 | 底層節(jié)點動態(tài)開辟,小節(jié)點容易造成內(nèi)存碎片,空間利用率低,緩存利用率低 |
迭 代 器 | 原生態(tài)指針 | 對原生態(tài)指針(節(jié)點指針)進(jìn)行封裝 |
迭 代 器 失 效 | 在插入元素時,要給所有的迭代器重新賦值,因為插入元素有可能會導(dǎo)致重新擴容,致使原來迭代器失效,刪除時,當(dāng)前迭代器需要重新賦值否則會失效 | 插入元素不會導(dǎo)致迭代器失效,刪除元素時,只會導(dǎo)致當(dāng)前迭代器失效,其他迭代器不受影響 |
使 用 場 景 | 需要高效存儲,支持隨機訪問,不關(guān)心插入刪除效率 | 大量插入和刪除操作,不關(guān)心隨機訪問 |
?list的模擬實現(xiàn)十分有趣,這里需要注意,list本身和list的節(jié)點是不同的結(jié)構(gòu),所以需要分開設(shè)計。成員都是只需淺拷貝,所以拷貝構(gòu)造,析構(gòu) ,重載 = 都可以使用默認(rèn)。
list?iterator也需要多帶帶設(shè)計,因為原生指針已經(jīng)無法滿足迭代器需求,所以需要封裝,讓它像一個指針一樣完成訪問操作。
通過template
#include #include #include #include #include #include using namespace std;namespace Zht{ template struct _list_node //list本身和list的節(jié)點是不同的結(jié)構(gòu),所以需要分開設(shè)計,這里是list節(jié)點的結(jié)構(gòu) { T val; //數(shù)據(jù) _list_node* _next; //下一個節(jié)點指針 _list_node* _prev; //上一個 _list_node(const T& val = T()) //構(gòu)造節(jié)點 :val(val) //傳的參 ,_prev(nullptr) ,_next(nullptr) { } }; template struct _list_iterator { typedef _list_node node; typedef _list_iterator self; node* _pnode; //迭代器本質(zhì)上是指針 _list_iterator(node* pnode) //構(gòu)造函數(shù) :_pnode(pnode) { } //這里,成員都是只需淺拷貝,所以拷貝構(gòu)造,析構(gòu) ,重載 = 都可以使用默認(rèn) Ref operator*() //重載*,通過Ref靈活的調(diào)整const和普通。 { return _pnode->val; } bool operator!=(const self& s) const { return _pnode != s._pnode; } bool operator==(const self& s) const { return _pnode == s._pnode; } self& operator++() //++就是指向下一個節(jié)點 { _pnode = _pnode->_next; return *this; } self operator++(int) //C++規(guī)定后綴調(diào)用需要有一個int型參數(shù)作為區(qū)分前綴與后綴調(diào)用的區(qū)別 { self tmp (*this); ++*this; return tmp; //*this++后++ } self& operator--() { _pnode = _pnode->_prev; return *this; } self operator--(int) { self tmp (*this); --*this; return tmp; } Ptr operator->() { return &(operator*()); } }; template class list { typedef _list_node node; public: typedef _list_iterator iterator; typedef _list_iterator const_iterator; list() //構(gòu)造函數(shù),構(gòu)造哨兵位 { _head = new node; //開一個節(jié)點 _head->_next = _head; //初始化節(jié)點 _head->_prev = _head; } template list(Iterator first, Iterator last) { _head = new node; _head->_next = _head; _head->_prev = _head; while(first != last) { push_back(*first); first++; } } list(const list& It) { _head = new node; //構(gòu)造哨兵節(jié)點 _head->_next = _head; _head->_prev = _head; for(const auto& e : It) //逐個尾插 { push_back(e); } } list& operator=(list It) { swap(_head, It._head); return *this; } ~list() { clear(); delete _head; _head = nullptr; } iterator begin() { return iterator(_head->_next); } const_iterator begin() const //調(diào)用const的迭代器,返回一個用_head->next構(gòu)造的迭代器對象 { return const_iterator(_head->_next); } iterator end() { return iterator(_head); } const_iterator end() const { return const_iterator(_head); } void push_back(const T& x) //只有哨兵位的也可以通用 { /* node* newnode = new node(x); //創(chuàng)建新節(jié)點 node* tail = _head->_prev; //當(dāng)前的最后一個節(jié)點 tail->_next = newnode; newnode->_next = _head; newnode->_prev = tail; _head->_prev = newnode;*/ insert(iterator(end()), x); //前一個就是尾 } void push_front(const T& x) { insert(iterator(begin),x); } void pop_back() { erase(iterator(--end())); } void pop_front() { erase(iterator(begin())); } iterator insert(iterator pos, const T& val) //pos位置前插入 { node* newnode = new node(val); node* tail = pos._pnode; newnode->_next = tail; newnode->_prev = tail->_prev; newnode->_prev->_next = newnode; //還要讓前一個指向自己 pos._pnode->_prev = newnode; return iterator(newnode); //需要返回迭代器; } iterator erase(iterator pos) //刪除pos位置 { assert(pos._pnode); assert(pos != end()); node* tail = pos._pnode; node* ret = tail->_next; tail->_prev->_next = tail->_next; tail->_next->_prev = tail->_prev; delete tail; return iterator(ret); //返回下一個 } bool empty() { return begin() == end(); } size_t size() { size_t sz = 0; iterator it = begin(); while(it != end()) { sz++; it++; } return sz; } void clear() { iterator it = begin(); while(it != end()) { erase(it); it++; } } private: node* _head; }; void PrintList(const list& It) { list::const_iterator it = It.begin(); while(it != It.end()) { cout << *it < lt; lt.push_back(1); lt.push_back(2); lt.push_back(3); lt.push_back(4); list::iterator it = lt.begin(); while (it != lt.end()) { *it += 1; cout << *it << " "; ++it; } cout << endl; for (auto e : lt) { cout << e << " "; } cout << endl; PrintList(lt); }}
?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/121133.html
摘要:本文介紹了類的常用接口的使用,并對其進(jìn)行了模擬實現(xiàn),對模擬實現(xiàn)中涉及到的深淺拷貝問題進(jìn)行了解析。在此之前,必須提到一個經(jīng)典問題。為了解決淺拷貝問題,所以中引入了深拷貝。但是實際使用中需要是第一個形參對象,才能正常使用。 本文介紹了string類的常用接口的使用,并對其進(jìn)行了模擬實現(xiàn),對模擬實...
摘要:函數(shù)底層實際上是對指針的操作隸書向,范圍內(nèi)比較等于的第一個元素返回迭代器。指定位置元素的刪除操作使用查找所在位置的刪除位置的數(shù)據(jù),導(dǎo)致迭代器失效。因此刪除中任意位置上元素時,就認(rèn)為該位置迭代器失效了。 ...
摘要:并且由于的連續(xù)性,且循環(huán)中有迭代器的自加,所以在刪除一個元素后,迭代器需要減。隸書方案二與方案一在迭代器的處理上是類似的,不過對元素的訪問采用了迭代器的方法。 一、...
摘要:對類采用三個模板來實現(xiàn)迭代器。楷體類中和模板定義分別對應(yīng)迭代器中模板定義的楷體采用向上傳值的方式,傳入不同值來采用不同迭代器。首先是迭代器的,分為前置和后置。迭代器的和都是獲取迭代器所對應(yīng)的值。唯一的差別就是就是用到了迭代器。 ...
摘要:結(jié)果我們發(fā)現(xiàn),好像沒多大問題,但是我們嘗試修改迭代器里面的內(nèi)容時,卻發(fā)現(xiàn)能修改成功。注意為兩個迭代器之間的距離。報錯這里的報錯說的是不在我們的迭代器當(dāng)中,這個是對我們迭代器類型的一個檢查。當(dāng)中為迭代器添加了如下聲明來解決這個問題。 ...
閱讀 2293·2021-11-10 11:35
閱讀 912·2021-09-26 09:55
閱讀 2404·2021-09-22 15:22
閱讀 2327·2021-09-22 15:17
閱讀 3697·2021-09-09 09:33
閱讀 1833·2019-08-30 11:22
閱讀 975·2019-08-30 10:57
閱讀 649·2019-08-29 16:10