4 2 list原始碼分析

2022-06-25 19:12:07 字數 4313 閱讀 5257

list概述

list底層為非連續區間,即鍊錶(實質上是乙個雙向迴圈鍊錶)

list每次插入或者刪除乙個元素,就配置和釋放乙個元素空間,對於任何位置的原屬插入或原屬移除,list永遠為常數時間。

list的節點

首先要知道,list本身和list的節點是不同的,如果我們宣告乙個list,裡面放了100w個元素,然後執行sizeof,會發現sizeof的結果並不是100w。這就是因為容器所管理的記憶體空間大小和容器本身的大小是不一樣的。

又如下測試**:

#include int main()
我的電腦為64位機,指標大小為8,可以看出,對list進行sizeof操作,其為24,而不是100,這也就能映襯上文所說的「容器所管理的記憶體空間大小和容器本身的大小是不一樣的」。那麼這24個byte是什麼呢?這就得慢慢分析源**了。

list的節點(node)定義如下,由乙個指向前乙個節點的指標,指向後乙個節點的指標,和資料三個部分構成:

template struct __list_node ;
list的迭代器

list的底層節點不能保證其在記憶體中連續存在,因此list的迭代器是不可能實現隨機訪問的,只能靠next和prev兩根指標的移動來進行操作。這樣的迭代器是雙向迭代器(bidirectional_iterator),即只能向前和向後移動。

templatestruct __list_iterator 

__list_iterator(link_type x) : node(x) {}

__list_iterator(const iterator& x) : node(x.node) {}

// 過載了iterator必須的操作符

// 解引用,取資料

reference operator*() const

// 指標使用->訪問資料成員

pointer operator->() const

// ++iter,iter通過next指向下乙個元素

self& operator++()

self operator++(int)

// --iter,iter通過prev指向上乙個元素

self& operator--()

self operator--(int)

bool operator==(const self& x) const

bool operator!=(const self& x) const

};

list有乙個重要的性質:插入(insert)和接合(splice)操作不回造成原有的list迭代器失效,這在vector是不成立的。list的元素刪除操作(erase)也只會讓指向「被刪除元素」的迭代器失效,其他迭代器不受影響。

list的資料結構

list的底層資料結構就是乙個雙向迴圈鍊錶,要表示這個雙向迴圈鍊錶十分的簡單,就用乙個節點(node)即可(這樣可以說明為什麼上面sizeof(list)=24了,乙個指標8位元組(64位機),prev、next2個指標和乙個,這裡有個坑,以後再補嗚嗚嗚)。我們在資料結構中學過,一般鍊錶有乙個頭節點,在list中也是一樣的,只不過為了滿足stl迭代器前閉後開這個特性,使得begin()為node->next,end()為node。可結合**與圖一起理解。

根據上圖,不難得出關於迭代器的幾個操作如下:

// node 指向尾節點的下一位置,因此 node 符合stl對 end 的定義。

iterator begin()

iterator end()

bool empty() const

size_type size() const

// 取頭節點的內容

reference front()

// 取尾節點的內容

reference back()

list的構造與析構

直接上建構函式和析構函式吧,看**就能說明問題!

template class list 

protected:

// 初始化

void empty_initialize()

// 析構函式

~list()

// 實現在下面,清除所有節點

void clear();

// 為結點分配記憶體

link_type get_node()

// **記憶體

void put_node(link_type p)

// 構造node

link_type create_node(const t& x)

// 銷毀node

void destroy_node(link_type p)

};// 清除所有節點

template void list::clear()

// 恢復 node 原始狀態

node->next = node;

node->prev = node;

}

list的其他操作

list成員函式的實現其實就是對環狀雙向鍊錶的操作。

首先是insert、erase、transfer的實現,關於插入刪除大部分都呼叫這三個函式,實際上就是改變結點pre跟next指標的指向。

iterator insert(iterator position, const t& x) 

iterator erase(iterator position)

// 將[first, last)插入到position位置(可以是同乙個鍊錶)

void transfer(iterator position, iterator first, iterator last)

}

list的對外介面:

void push_front(const t& x) 

void push_back(const t& x)

void pop_front()

void pop_back()

void swap(list& x)

// splice有很多過載版本

// 將 x 接合於 position 所指位置之前。x 必須不同於 *this。

void splice(iterator position, list& x)

// 將 i 所指元素接合於 position 所指位置之前。position 和i 可指向同乙個list。

void splice(iterator position, list&, iterator i)

// 將 [first,last) 內的所有元素接合於 position 所指位置之前。

// position 和[first,last)可指向同乙個list,

// 但position不能位於[first,last)之內。

void splice(iterator position, list&, iterator first, iterator last)

// merge函式實現跟歸併排序中合併的操作類似

template void list::merge(list& x)

else

++first1;

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

}// reserse函式每次都呼叫transfer將結點插入到begin()之前

template void list::reverse()

}// list必須使用自己的sort()成員函式 因為stl演算法中的sort()只接受ramdonaccessiterator

// 該函式採用的是quick sort

template void list::sort()

carry.swap(counter[i]);

if (i == fill) ++fill;

} for (int i = 1; i < fill; ++i)

counter[i].merge(counter[i-1]);

swap(counter[fill-1]);

}

List原始碼分析

list 是繼承colection的介面 我們主要學習他的實現類 arraylist 和 linkedlist arraylist是基於陣列實現的 與陣列不同的是 它可以存放不同的資料型別的資料而且長度不定 我們分析一下他的底程實現 新增過程 public boolean add e e 如何做到長...

STL原始碼分析 List

鍊錶是一種線性表,但不會按照線性的順序儲存。鍊錶每次插入和刪除乙個元素,只配置或者釋放乙個元素空間,對於任何位置的元素的插入或者刪除,list永遠是常量時間複雜度。template struct listnode 節點物件包含兩個節點物件指標,分別指向前乙個節點和後乙個節點,還有乙個節點物件存放的資...

Kettle 4 2原始碼分析

乙個job項代表etl控制流中的一項邏輯任務。job項將會順序執行,每個job項會產生乙個結果,能作為別的分支上job項的條件。圖 1 job項示例 圖 2 job entry類圖結構 jobentryinte ce是job entry外掛程式的主要實現介面。主要包含以下功能 1 儲存job ent...