摘要:對(duì)類(lèi)采用三個(gè)模板來(lái)實(shí)現(xiàn)迭代器??w類(lèi)中和模板定義分別對(duì)應(yīng)迭代器中模板定義的楷體采用向上傳值的方式,傳入不同值來(lái)采用不同迭代器。首先是迭代器的,分為前置和后置。迭代器的和都是獲取迭代器所對(duì)應(yīng)的值。唯一的差別就是就是用到了迭代器。
一、list底層實(shí)現(xiàn)機(jī)制刨析
前面在講 STL list 容器時(shí)提到,該容器的底層是用雙向鏈表實(shí)現(xiàn)的,甚至一些 STL 版本中(比如 SGI STL),list 容器的底層實(shí)現(xiàn)使用的是雙向循環(huán)鏈表
圖 1 雙向鏈表( a) )和雙向循環(huán)鏈表( b) )
圖 1 中,node 表示鏈表的頭指針。
如圖 1 所示,使用鏈表存儲(chǔ)數(shù)據(jù),并不會(huì)將它們存儲(chǔ)到一整塊連續(xù)的內(nèi)存空間中。恰恰相反,各元素占用的存儲(chǔ)空間(又稱(chēng)為節(jié)點(diǎn))是獨(dú)立的、分散的,它們之間的線性關(guān)系通過(guò)指針(圖 1 以箭頭表示)來(lái)維持。
通過(guò)圖 1 可以看到,雙向鏈表的各個(gè)節(jié)點(diǎn)中存儲(chǔ)的不僅僅是元素的值,還應(yīng)包含 2 個(gè)指針,分別指向前一個(gè)元素和后一個(gè)元素。
通過(guò)查看 list 容器的源碼實(shí)現(xiàn),其對(duì)節(jié)點(diǎn)的定義如下:
template<class T>struct list_node { T data; struct list_node<T>* next;//節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)的地址 struct list_node<T>* prev;//節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)的地址 list_node(const T date) : data(date), next(nullptr) , prev(nullptr) {} };
注意,為了方便讀者理解,此代碼以及本節(jié)后續(xù)代碼,都省略了和本節(jié)核心內(nèi)容不相關(guān)的內(nèi)容,如果讀者對(duì)此部分感興趣,可查看 list 容器實(shí)現(xiàn)源碼。
可以看到,list 容器定義的每個(gè)節(jié)點(diǎn)中,都包含 *prev、*next 和 data。其中,prev 指針用于指向前一個(gè)節(jié)點(diǎn);next 指針用于指向后一個(gè)節(jié)點(diǎn);data 用于存儲(chǔ)當(dāng)前元素的值
一、list的核心框架接口的模擬實(shí)現(xiàn)
1.list迭代器
STL容器迭代器有兩種實(shí)現(xiàn)方式,具體應(yīng)根據(jù)容器底層數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn):
1)原生指針,比如:vector string
2). 將原生態(tài)指針進(jìn)行封裝,因迭代器使用形式與指針完全相同,因此在自定義的類(lèi)中必須實(shí)現(xiàn)以下
方法:
//迭代器結(jié)構(gòu)體 template<class T, class Ref, class Ptr> struct list_Iterator { typedef list_node<T> Node; typedef list_Iterator<T, Ref, Ptr> Self; Node* node; public: bool operator!=(const Self& iter) { return node != iter.node; } /* list_Iterator& operator++(){ node = node->next ; return *this; }*/ //前置++ Self& operator ++() { node = node->next; return *this; } //后置++和前置++構(gòu)成重載 Self& operator ++(int) { node = node->next; return *this; } list_Iterator(Node* _node) :node(_node) { } Self& operator--() { node = node->prev; return *this; } Self& operator--(int) { node = node->prev; return *this; } Ptr operator*()const { return node->data; } Ptr operator->() { return &node->data; } bool operator !=(const Self& it) const { return node != it->node; } bool operator ==( const Self& it) const { return node == it.node; } };
list迭代器分為ierator和const_iterator迭代器,本來(lái)分別實(shí)現(xiàn)他的iterator迭代器和const_iterator迭代器。但是c++中有模板作為支撐。對(duì)list類(lèi)采用三個(gè)模板來(lái)實(shí)現(xiàn)迭代器。
typedef list_Iterator<T, T*, T&> iterator; typedef list_Iterator<T, const T*, const T&> const_iterator;
list類(lèi)中iterator和const_iterator模板定義分別對(duì)應(yīng)迭代器中模板定義的:
template<class T, class Ref, class Ptr>
采用向上傳值的方式,傳入不同值來(lái)采用不同迭代器。iterator傳入的
const_iterator傳入的是
迭代器根據(jù)傳入不同值來(lái)判斷采用的是那種迭代器。
首先是迭代器的++,分為前置++和后置++。兩種運(yùn)算符重載根據(jù)參數(shù)來(lái)構(gòu)成運(yùn)算符重載。
//前置++ Self& operator ++() { node = node->next; return *this; } //后置++和前置++構(gòu)成重載 Self& operator ++(int) { node = node->next; return *this;
迭代器前置++和后置++都是將node->nex來(lái)賦給node來(lái)達(dá)到迭代器的移動(dòng)。
迭代器的operator*()和operator->()都是獲取迭代器所對(duì)應(yīng)的值。
但是operator*()返回的是模板的&可以都也可以寫(xiě)。
而operator->()返回的是模板對(duì)應(yīng)指針。
Ptr operator*()const { return node->data; } Ptr operator->() { return &node->data; }
list其他接口的實(shí)現(xiàn):
list接口實(shí)現(xiàn)其實(shí)和鏈表基本差不了多少。唯一的差別就是list就是用到了迭代器。
2.1 list的insert()
數(shù)是一個(gè)迭代器和要插入的值X
iterator insert(iterator pos, const T& x) { Node* cue = pos.node; Node* prev = cue->prev; Node* newnode = new Node(x); prev->next = newnode; newnode->prev = prev; newnode->next = cue; cue->prev = newnode; return iterator(newnode); }
先保存pos對(duì)應(yīng)的模板值接著參照鏈表的在pos的前一個(gè)節(jié)點(diǎn)和pos節(jié)點(diǎn)鏈接起來(lái),返回pos’節(jié)點(diǎn)前一個(gè)節(jié)點(diǎn)的迭代器。
2.2 list的push_back()
void push_back(const T& t) { /* Node* l = head->prev; Node* newnode = new Node(t); newnode->prev = l; l->next = newnode; head->prev = newnode; newnode->next = head;*/ insert(end(), t); }
list的push_back()只需調(diào)用insert()但是參數(shù)迭代器是end().
2.3 list的erase()
iterator erase(iterator iter) { assert(iter != end()); Node* cur = iter.node; Node* prev = cur->prev; Node* Next = cur->next; prev->next = Next; Next->prev = prev; delete cur; return iterator(Next); }
list的erase()傳入要?jiǎng)h所對(duì)應(yīng)的迭代器。然后保存迭代器所對(duì)應(yīng)的模板值找到前一個(gè)節(jié)點(diǎn)和后一個(gè)節(jié)點(diǎn)將錢(qián)一個(gè)節(jié)點(diǎn)后一個(gè)節(jié)點(diǎn)連接起來(lái)。釋放pos對(duì)應(yīng)的節(jié)點(diǎn)。返回pos下一個(gè)節(jié)點(diǎn)對(duì)應(yīng)的指針。
2.4 list構(gòu)造
在list無(wú)參構(gòu)造將head的next和prev都指向自己,早就循環(huán)鏈表。
list() { head = new Node(T()); head->next = head; head->prev = head; }
list(IteraterFirst first,IteraterFirstEnd en) { head = new Node(T()); head->next = head; head->prev = head; while (first!=en) { push_back(*first); first++; } }
傳統(tǒng)寫(xiě)法 list(const list<T>& x) { head = new Node(T()); head->next = head; head->prev = head; const_iterator i = x.begin(); while (i != x.end()) { push_back(*i); i++; } }現(xiàn)代寫(xiě)法 list(const list<T>& t) { head = new Node(T()); head->next = head; head->prev = head; list<T> temp(t.begin(),t.end()); swap(head, temp.head); } list<T> operator=(const list<T> lt) { swap(head, lt.head); return *this; }
2.5 其他接口大多都是參照inser()和erase()實(shí)現(xiàn)的
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/125654.html
摘要:檢查數(shù)據(jù)是否是格式判斷是否為有效郵件地址判斷是否為有效網(wǎng)址判斷字符串是否為空判斷是否為指定長(zhǎng)度內(nèi)字符串判斷是否為合法用戶名判斷是否為合法用戶密碼判斷是否為合法電話號(hào)碼判斷是否是某一范圍內(nèi)的合法值判斷是否為合法郵編固定長(zhǎng)度判斷上傳文件的擴(kuò)展名 // ※CheckMoney($C_Money) 檢查數(shù)據(jù)是否是99999.99格式// ※CheckEmailAddr($C_mailaddr)...
摘要:讀到一個(gè)非數(shù)字非英文字母非下劃線字符。此時(shí)立即跳轉(zhuǎn)回狀態(tài)。以一個(gè)雙引號(hào)開(kāi)始,并以一個(gè)雙引號(hào)結(jié)束。另外,在讀和時(shí)源代碼不許結(jié)束,即讀到符號(hào),若結(jié)束,則判定為詞法錯(cuò)誤。對(duì)于而言,也有一些其他的詞法錯(cuò)誤判定,如,不能換行。 對(duì)于非 Normal 狀態(tài),我只需要關(guān)心兩個(gè)過(guò)程: 何時(shí)從 Normal 跳轉(zhuǎn)到該狀態(tài); 何時(shí)從該狀態(tài)跳回 Normal 狀態(tài)。 在上一章中,我已經(jīng)寫(xiě)好了從 Nor...
摘要:簡(jiǎn)評(píng)網(wǎng)格模塊是創(chuàng)建網(wǎng)站模型的絕佳工具。如果你對(duì)網(wǎng)格完全陌生,你可能要瀏覽一下我的分鐘介紹網(wǎng)格的文章。每一行代表一行,每一個(gè)字符,,,代表一個(gè)網(wǎng)格元素。無(wú)論標(biāo)簽在標(biāo)記中是如何放置的,我們都能隨意轉(zhuǎn)換。這被稱(chēng)為源代碼的獨(dú)立性,這是的一大進(jìn)步。 簡(jiǎn)評(píng):CSS 網(wǎng)格模塊是創(chuàng)建網(wǎng)站模型的絕佳工具。它是我嘗試過(guò)的任何其他系統(tǒng)中最快讓你體驗(yàn)布局的工具。 我們的網(wǎng)格 我們將從模仿一個(gè)經(jīng)典網(wǎng)站的非?;?..
摘要:調(diào)用以回調(diào)函數(shù)地址為參數(shù)的函數(shù)這個(gè)主題就稍微繞一些了,也就是說(shuō)在接口中,需要傳入回調(diào)函數(shù)作為參數(shù)。這個(gè)問(wèn)題在中也可以解決,并且回調(diào)函數(shù)可以用定義。代碼代碼很簡(jiǎn)單回調(diào)函數(shù)的傳入?yún)?shù)為,返回參數(shù)也是。 項(xiàng)目中要對(duì)一個(gè)用 C 編寫(xiě)的 .so 庫(kù)進(jìn)行邏輯自測(cè)。這項(xiàng)工作,考慮到靈活性,我首先考慮用 Python 來(lái)完成。 研究了一些資料,采用 python 的 ctypes 來(lái)完成這項(xiàng)工作。已經(jīng)...
閱讀 3792·2023-01-11 11:02
閱讀 4299·2023-01-11 11:02
閱讀 3121·2023-01-11 11:02
閱讀 5231·2023-01-11 11:02
閱讀 4793·2023-01-11 11:02
閱讀 5568·2023-01-11 11:02
閱讀 5371·2023-01-11 11:02
閱讀 4070·2023-01-11 11:02