成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

[C/C++ -STL]list模擬實(shí)現(xiàn)及l(fā)ist迭代器底層刨析

不知名網(wǎng)友 / 1712人閱讀

摘要:對類采用三個模板來實(shí)現(xiàn)迭代器。楷體類中和模板定義分別對應(yīng)迭代器中模板定義的楷體采用向上傳值的方式,傳入不同值來采用不同迭代器。首先是迭代器的,分為前置和后置。迭代器的和都是獲取迭代器所對應(yīng)的值。唯一的差別就是就是用到了迭代器。

一、list底層實(shí)現(xiàn)機(jī)制刨析
前面在講 STL list 容器時提到,該容器的底層是用雙向鏈表實(shí)現(xiàn)的,甚至一些 STL 版本中(比如 SGI STL),list 容器的底層實(shí)現(xiàn)使用的是雙向循環(huán)鏈表

圖 1 雙向鏈表( a) )和雙向循環(huán)鏈表( b) )
圖 1 中,node 表示鏈表的頭指針。
如圖 1 所示,使用鏈表存儲數(shù)據(jù),并不會將它們存儲到一整塊連續(xù)的內(nèi)存空間中。恰恰相反,各元素占用的存儲空間(又稱為節(jié)點(diǎn))是獨(dú)立的、分散的,它們之間的線性關(guān)系通過指針(圖 1 以箭頭表示)來維持。
通過圖 1 可以看到,雙向鏈表的各個節(jié)點(diǎn)中存儲的不僅僅是元素的值,還應(yīng)包含 2 個指針,分別指向前一個元素和后一個元素。

通過查看 list 容器的源碼實(shí)現(xiàn),其對節(jié)點(diǎn)的定義如下:

template<class T>struct list_node {	T data;	struct list_node<T>* next;//節(jié)點(diǎn)的下一個節(jié)點(diǎn)的地址	struct list_node<T>* prev;//節(jié)點(diǎn)的上一個節(jié)點(diǎn)的地址	list_node(const T date)		:		data(date),		next(nullptr)		, prev(nullptr)	{}	};

注意,為了方便讀者理解,此代碼以及本節(jié)后續(xù)代碼,都省略了和本節(jié)核心內(nèi)容不相關(guān)的內(nèi)容,如果讀者對此部分感興趣,可查看 list 容器實(shí)現(xiàn)源碼。

可以看到,list 容器定義的每個節(jié)點(diǎn)中,都包含 *prev、*next 和 data。其中,prev 指針用于指向前一個節(jié)點(diǎn);next 指針用于指向后一個節(jié)點(diǎn);data 用于存儲當(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)行封裝,因迭代器使用形式與指針完全相同,因此在自定義的類中必須實(shí)現(xiàn)以下
方法:

  1. 指針可以解引用,迭代器的類中必須重載operator*()
  2. 指針可以通過->訪問其所指空間成員,迭代器類中必須重載oprator->()
  3. 指針可以++向后移動,迭代器類中必須重載operator++()與operator++(int)
    至于operator–()/operator–(int)釋放需要重載,根據(jù)具體的結(jié)構(gòu)來抉擇,雙向鏈表可以向前 移動,所以需要重載,如果是forward_list就不需要重載–
  4. 迭代器需要進(jìn)行是否相等的比較,因此還需要重載operator==()與operator!=():
//迭代器結(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迭代器,本來分別實(shí)現(xiàn)他的iterator迭代器和const_iterator迭代器。但是c++中有模板作為支撐。對list類采用三個模板來實(shí)現(xiàn)迭代器。

	typedef list_Iterator<T, T*, T&> iterator;		typedef list_Iterator<T, const T*, const T&> const_iterator;

list類中iterator和const_iterator模板定義分別對應(yīng)迭代器中模板定義的:

	template<class T, class Ref, class Ptr>

采用向上傳值的方式,傳入不同值來采用不同迭代器。iterator傳入的對應(yīng)的是.
const_iterator傳入的是對應(yīng)的是,
迭代器根據(jù)傳入不同值來判斷采用的是那種迭代器。
首先是迭代器的++,分為前置++和后置++。兩種運(yùn)算符重載根據(jù)參數(shù)來構(gòu)成運(yùn)算符重載。

	  //前置++		Self& operator ++()		{			node = node->next;			return *this;		}		//后置++和前置++構(gòu)成重載		Self& operator ++(int)		{			node = node->next;			return *this;		

迭代器前置++和后置++都是將node->nex來賦給node來達(dá)到迭代器的移動。
迭代器的operator*()和operator->()都是獲取迭代器所對應(yīng)的值。
但是operator*()返回的是模板的&可以都也可以寫。
而operator->()返回的是模板對應(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ù)是一個迭代器和要插入的值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對應(yīng)的模板值接著參照鏈表的在pos的前一個節(jié)點(diǎn)和pos節(jié)點(diǎn)鏈接起來,返回pos’節(jié)點(diǎn)前一個節(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()傳入要刪所對應(yīng)的迭代器。然后保存迭代器所對應(yīng)的模板值找到前一個節(jié)點(diǎn)和后一個節(jié)點(diǎn)將錢一個節(jié)點(diǎn)后一個節(jié)點(diǎn)連接起來。釋放pos對應(yīng)的節(jié)點(diǎn)。返回pos下一個節(jié)點(diǎn)對應(yīng)的指針。
2.4 list構(gòu)造
在list無參構(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)寫法	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)代寫法	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)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/125654.html

相關(guān)文章

  • php 驗(yàn)證格式的函數(shù)總結(jié)

    摘要:檢查數(shù)據(jù)是否是格式判斷是否為有效郵件地址判斷是否為有效網(wǎng)址判斷字符串是否為空判斷是否為指定長度內(nèi)字符串判斷是否為合法用戶名判斷是否為合法用戶密碼判斷是否為合法電話號碼判斷是否是某一范圍內(nèi)的合法值判斷是否為合法郵編固定長度判斷上傳文件的擴(kuò)展名 // ※CheckMoney($C_Money) 檢查數(shù)據(jù)是否是99999.99格式// ※CheckEmailAddr($C_mailaddr)...

    lushan 評論0 收藏0
  • 從零開始寫個編譯器吧 - 開始寫詞法分析器(2)

    摘要:讀到一個非數(shù)字非英文字母非下劃線字符。此時立即跳轉(zhuǎn)回狀態(tài)。以一個雙引號開始,并以一個雙引號結(jié)束。另外,在讀和時源代碼不許結(jié)束,即讀到符號,若結(jié)束,則判定為詞法錯誤。對于而言,也有一些其他的詞法錯誤判定,如,不能換行。 對于非 Normal 狀態(tài),我只需要關(guān)心兩個過程: 何時從 Normal 跳轉(zhuǎn)到該狀態(tài); 何時從該狀態(tài)跳回 Normal 狀態(tài)。 在上一章中,我已經(jīng)寫好了從 Nor...

    MarvinZhang 評論0 收藏0
  • 如何用 CSS 網(wǎng)格快速做出網(wǎng)站原型

    摘要:簡評網(wǎng)格模塊是創(chuàng)建網(wǎng)站模型的絕佳工具。如果你對網(wǎng)格完全陌生,你可能要瀏覽一下我的分鐘介紹網(wǎng)格的文章。每一行代表一行,每一個字符,,,代表一個網(wǎng)格元素。無論標(biāo)簽在標(biāo)記中是如何放置的,我們都能隨意轉(zhuǎn)換。這被稱為源代碼的獨(dú)立性,這是的一大進(jìn)步。 簡評:CSS 網(wǎng)格模塊是創(chuàng)建網(wǎng)站模型的絕佳工具。它是我嘗試過的任何其他系統(tǒng)中最快讓你體驗(yàn)布局的工具。 我們的網(wǎng)格 我們將從模仿一個經(jīng)典網(wǎng)站的非常基本...

    thursday 評論0 收藏0
  • Python 調(diào)用 C 動態(tài)鏈接庫,包括結(jié)構(gòu)體參數(shù)、回調(diào)函數(shù)等

    摘要:調(diào)用以回調(diào)函數(shù)地址為參數(shù)的函數(shù)這個主題就稍微繞一些了,也就是說在接口中,需要傳入回調(diào)函數(shù)作為參數(shù)。這個問題在中也可以解決,并且回調(diào)函數(shù)可以用定義。代碼代碼很簡單回調(diào)函數(shù)的傳入?yún)?shù)為,返回參數(shù)也是。 項(xiàng)目中要對一個用 C 編寫的 .so 庫進(jìn)行邏輯自測。這項(xiàng)工作,考慮到靈活性,我首先考慮用 Python 來完成。 研究了一些資料,采用 python 的 ctypes 來完成這項(xiàng)工作。已經(jīng)...

    NickZhou 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<