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