06.25 STL源碼分析之list

STL用環狀雙向鏈表來實現list,方法和leveldb的緩存環狀鏈表一樣,鏈表持有一個傀儡節點,不存儲數據,只為這個鏈表的入口。迭代鏈表時,首先通過鏈表獲得這個這個傀儡節點,然後通過next迭代所有數據。

STL將鏈表的傀儡節點作為鏈表的end節點,傀儡節點的next為begin節點,這樣以來,就可以用[begin,end)這種左閉右開的形式來表示迭代器範圍,和其他容器保持一致。

list節點結構

STL源碼分析之list

因為是雙向鏈表,所以有兩個指針,分別指向前向指針和後向指針。

迭代器類型

因為list數據不是存儲在連續的內存內,所以不能通過指針的加1減一來實現迭代器。list數據是通過指針鏈表結合在一起的,所以為了迭代所有數據,必須通過上個節點找到下個節點的地址,進而訪問下個節點。list迭代器就是用這個原理,實現如下:

STL源碼分析之list

STL源碼分析之list

以上就是list的迭代器實現,只實現了迭代器的++,--,取值,成員調用四個基本操作,並沒有像vector迭代器那樣的+n操作,主要是因為地址不連續。

list實現

接下來看下list實現,list只有一個成員變量,就是那個傀儡節點,也是end節點。

先來看構造函數:

STL源碼分析之list

這個構造函數為默認構造函數,就是創建一個節點,然後前後指向自己而已。說到配置器,由於list用的是自己定義節點結構體,所以也定義了相應類型的配置器。

STL源碼分析之list

list還定義幾種構造函數,用n個值來初始化list,將另一個list的一部分數據來初始化list和複製構造函數。

STL源碼分析之list

這幾個函數調用了fill_initialize和range_initialize,來看下這兩個函數。

STL源碼分析之list

這兩個函數最後分別調用了insert函數的不同版本。一起來看下這兩個insert函數。

STL源碼分析之list

這兩個函數通過循環調用 iterator insert(iterator position, const T& x) 這個insert版本,將數據一個一個插入到position之前,初始時就是插入到傀儡節點後面,形成初始鏈表,源碼如下:

STL源碼分析之list

最後看下析構函數

STL源碼分析之list

這兩個函數,clear是清空鏈表所有數據,然後put_node是將傀儡節點回收了。

一些小函數

STL源碼分析之list

最後一個交換兩個鏈表,只需要通過標準函數庫的swap函數,交換兩個傀儡節點即可,因為傀儡節點是每個鏈表的入口。

一些常用函數

往鏈表前插一個元素,通過調用insert完成。

STL源碼分析之list

往鏈表尾巴插一個元素,也是通過insert函數完成。

STL源碼分析之list

移除一個元素

STL源碼分析之list

這個函數也很簡單,只需要將被移除節點的前後節點跳過當前節點即可。

前後刪除一個節點,用erase函數實現:

STL源碼分析之list


transfer函數

這個函數是很多list接口調用的函數。這個函數有點難看懂,我把《STL源碼剖析》上的圖截下來,容易理解:

STL源碼分析之list

;

源碼如下:

STL源碼分析之list

按著序號來讀那個示意圖,應該能看懂,本質上就那幾個關鍵節點的前後關係。

有了這個函數之後,就出現了一些很有用的函數:

STL源碼分析之list

remove函數

將數值為value的所有元素移除:

STL源碼分析之list

merge函數

合併兩個鏈表,前提是兩個鏈表必須有序,合併之後的鏈表也是有序的。merge之後,x鏈表被清空了。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

template <class>

void list::merge(list

& x) {

iterator first1 = begin();

iterator last1 = end();

iterator first2 = x.begin();

iterator last2 = x.end();

while (first1 != last1 && first2 != last2)

if (*first2 < *first1) {

iterator next = first2;

transfer(first1, first2, ++next);

first2 = next;

}

else

++first1;

if (first2 != last2) transfer(last1, first2, last2);

}

reverse函數

這個函數是用於將鏈表數據反序:

STL源碼分析之list

這裡要注意的是,在鏈表begin前插入元素,都將改變鏈表的begin。

sort函數

list不能使用STL的sort算法,因為STL的sort算法必須接受RamdonAccessIterator,而sort的迭代器為Bidirectional iterators,所以list自己實現了這個sort算法:

STL源碼分析之list

這個排序算法,本人看的也不是很懂,看了魚思故淵的博客,略懂程序執行流程。大家可以看他的博客。

當然list還提供了帶自定義比較的上述函數

STL源碼分析之list

list大概就這些就這些了。

看STL源碼真心可以學到東西,首先把基本數據結構複習了一遍,而且SGI裡的數據結構比平時寫的數據結構優秀多了。其次好好掌握了STL模板庫用法。最後就是學到一些細節的東西,比如int(),double()表示這種類型的默認值。


分享到:


相關文章: