1. 程式人生 > >【C++】STL常用容器總結之四:連結串列list

【C++】STL常用容器總結之四:連結串列list

5、連結串列list

List是每個節點包含前驅指標、後繼指標和資料域三個部分的雙向連結串列。List不提供隨機存取,訪問元素需要按順序走到需存取的元素,時間複雜度為O(n),在list的任何位置上執行插入或刪除操作都非常迅速,只需在list內部調整一下指標。list不僅是一個雙向連結串列,而且還是一個環狀雙向連結串列。所以它只需要一個指標,便可以完整實現整個連結串列。(這裡需要特別強調一下:list到底是不是雙向連結串列?有的書上說是,有的書上沒說,所以大家注意一下,這裡暫把list當作雙向連結串列,等博主找到資料再做解釋)
與向量vector相比,list允許快速的插入和刪除,且每次插入或刪除一個元素,就配置或釋放一個元素空間,對於任何位置的元素插入或元素移除,list永遠是常數時間。
List不再能夠像vector那樣以普通指標作為迭代器,因為其節點不保證在儲存空間中連續存在。list迭代器必須有能力指向list的節點,並有能力進行正確的遞增、遞減、取值、成員存取等操作。所謂list迭代器正確的遞增、遞減、取值、成員取用操作是指,遞增時指向下一個節點,遞減時指向上一個節點,取值時取的是節點的資料值,成員取用時取用的是節點的成員。
List有一個重要性質:插入操作(insert)和合並操作(splice)都不會造成原有的list迭代器失效。這在vector是不成立的,因為vector的插入操作可能造成記憶體重新配置,導致原有的迭代器全部失效。甚至list的元素刪除操作(erase)也只有“指向被刪除元素”的那個迭代器失效,其他迭代器不受任何影響。
在使用list類模版時,也必須包含相應的標頭檔案:#include<list>

,list物件的宣告與vector類似,這裡僅僅介紹一下list的成員函式。

1、宣告list容器

  1. list list1; // 宣告一個空的list1
  2. list list2 (4, 100); // 宣告以個含4個100的list2
  3. list list3 (list2.begin(), list2.end()); // 用list2的迭代器內容宣告list3
  4. list list4 (list3); // 宣告list4為list3的一個副本
  5. list list5(size); // 宣告一個含size個預設值為0的list5
  6. list1.~list(); // 登出list

2、list與vector不相同的一些操作

List與vector相同的一些操作,這裡僅列出函式名,不再進行具體說明:Begin/end/rbegin/rend/empty/size/Max_size/resize/insert/erase/swap/clear。
以下這些函式是list與vector不同的函式:

list<int> list1;

1、訪問list元素

  1. list1.front():返回第一個元素的值。
  2. list1.back():返回最後一個元素的值。

2、list元素的插入與刪除

  1. list1.push_front(x):把元素x插入到連結串列頭部。
  2. list1.pop_front():刪除第一個元素。
  3. list1.push_back(x):把元素x插入到連結串列尾部。
  4. list1.pop_back():刪除最後一個元素。
  5. list1.remove(val):刪除連結串列中所有值為val的元素。
  6. list1.remove_if(pred):刪除連結串列中謂詞pred為真的元素(謂詞即為元素儲存和檢索的描述,如std::less<>,std::greater<>那麼就按降序/升序排列,你也可以定義自己的謂詞)。
  7. list1.unique():刪除連結串列中所有重複的元素(這個函式博主在VS上測試的時候,並沒有刪除所有重複的元素,大家使用的時候最好也親測一下。。。)。
  8. list1.unique(pred):根據謂詞pred刪除所有重複的元素,使連結串列中沒有重複元素。

3、list拼接操作

  1. splice():連結串列拼接,引數position是迭代器而不是下標。
  2. list1.splice ( position, list2 ):將list2中的所有元素插入到list1中position處,list2會被清空,position仍然指向list1中的那個元素。
  3. list1.splice ( position, list2, iter ):將list2中iter處的元素插入到list1中position處,list2會將iter指向的元素刪除,iter失效。
  4. list1.splice ( position, list2, first, last ):將list2中[first,last)位置處的元素插入到list1的position處。

4、list合併操作

  1. merge(listref):連結串列合併:把listref所引用的連結串列中的所有元素插入到連結串列中,可指定合併規則。
  2. OutputIterator merge (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result);
  3. OutputIterator merge (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp); // 由於引數複雜,這裡列出了C++官網給出的原函式,具體的例子可以參考C++官網.

5、list排序操作

  1. sort():根據預設的謂詞對連結串列排序,預設升序。
  2. sort(pred):根據給定的謂詞對連結串列排序。

3、vector與list之間的區別

C++標準庫中,容器vector和list都可以用來存放一組型別相同的資料。而且二者不同於陣列的一點是,支援動態增長。但它們還是有幾點不同:
1. Vector是順序表,表示的是一塊連續的記憶體,元素被順序儲存;list是雙向連結串列,在記憶體中不一定連續。
2. 當數值記憶體不夠時,vector會重新申請一塊足夠大的連續記憶體,把原來的資料拷貝到新的記憶體裡面,再釋放舊空間;list因為不用考慮記憶體的連續,因此新增開銷比vector小。
3. List只能通過指標訪問元素,隨機訪問元素的效率特別低,在需要頻繁隨機存取元素時,使用vector更加合適。
4. 當向vector插入或者刪除一個元素時,需要複製移動待插入元素右邊的所有元素;因此在有頻繁插入刪除操作時,使用list更加合適。
5. Vector和deque支援隨機訪問,而list不支援隨機訪問,因此list不支援[ ]訪問。