1.關於list容器
list是一種序列式容器。list容器完成的功能實際上和資料結構中的雙向鍊錶是極其相似的,list中的資料元素是通過鍊錶指標串連成邏輯意義上的線性表,也就是list也具有鍊錶的主要優點,即:在鍊錶的任一位置進行元素的插入、刪除操作都是快速的。list的實現大概是這樣的:list的每個節點有三個域:前驅元素指標域、資料域和後繼元素指標域。前驅元素指標域儲存了前驅元素的首位址;資料域則是本節點的資料;後繼元素指標域則儲存了後繼元素的首位址。其實,list和迴圈鍊錶也有相似的地方,即:頭節點的前驅元素指標域儲存的是鍊錶中尾元素的首位址,list的尾節點的後繼元素指標域則儲存了頭節點的首位址,這樣,list實際上就構成了乙個雙向迴圈鏈。
由於list元素節點並不要求在一段連續的記憶體中,顯然在list中是不支援快速隨機訪問的,因此對於迭代器,只能通過「++」或「--」操作將迭代器移動到後繼/前驅節點元素處。而不能對迭代器進行+n或-n的操作,這點,是與vector等不同的地方。
我想把三個常用的序列式放在一起對比一下是有必要的:
vector :vector和built-in陣列類似,擁有一段連續的記憶體空間,能非常好的支援隨即訪問,即操作符,但由於它的記憶體空間是連續的,所以在中間進行插入和刪除會造成記憶體塊的拷貝,另外,當插入較多的元素後,預留記憶體空間可能不夠,需要重新申請一塊足夠大的記憶體並把原來的資料拷貝到新的記憶體空間。這些影響了vector的效率,但是實際上用的最多的還是vector容器,建議大多數時候使用vector效率一般是不錯的。
list:list就是資料結構中的雙向鍊錶(根據sgi stl源**),因此它的記憶體空間是不連續的,通過指標來進行資料的訪問,這個特點使得它的隨即訪問變的非常沒有效率,因此它沒有提供操作符的過載。但由於鍊錶的特點,它可以以很好的效率支援任意地方的刪除和插入。
deque:deque是乙個double-ended queue,它的具體實現不太清楚,但知道它具有以下兩個特點:它支援操作符,也就是支援隨即訪問,並且和vector的效率相差無幾,它支援在兩端的操作:push_back,push_front,pop_back,pop_front等,並且在兩端操作上與list的效率也差不多。
因此在實際使用時,如何選擇這三個容器中哪乙個,應根據你的需要而定,具體可以遵循下面的原則:
1. 如果你需要高效的隨即訪問,而不在乎插入和刪除的效率,使用vector
2. 如果你需要大量的插入和刪除,而不關心隨即訪問,則應使用list
3. 如果你需要隨即訪問,而且關心兩端資料的插入和刪除,則應使用deque。
2.list中常用的函式
2.1list中的建構函式:
list() 宣告乙個空列表;
list(n) 宣告乙個有n個元素的列表,每個元素都是由其預設建構函式t()構造出來的
list(n,val) 宣告乙個由n個元素的列表,每個元素都是由其複製建構函式t(val)得來的
list(n,val) 宣告乙個和上面一樣的列表
list(first,last) 宣告乙個列表,其元素的初始值**於由區間所指定的序列中的元素
2.2 begin()和end():通過呼叫list容器的成員函式begin()得到乙個指向容器起始位置的iterator,可以呼叫list容器的 end() 函式來得到list末端下一位置,相當於:int a[n]中的第n+1個位置a[n],實際上是不存在的,不能訪問,經常作為迴圈結束判斷結束條件使用。
2.3 push_back() 和push_front():使用list的成員函式push_back和push_front插入乙個元素到list中。其中push_back()從list的末端插入,而 push_front()實現的從list的頭部插入。
2.4 empty():利用empty() 判斷list是否為空。
2.5
resize():
如果呼叫resize(n)將list的長度改為只容納n個元素,超出的元素將被刪除,如果需要擴充套件那麼呼叫預設建構函式t()將元素加到list末端。如果呼叫resize(n,val),則擴充套件元素要呼叫建構函式t(val)函式進行元素構造,其餘部分相同。
2.6 clear():清空list中的所有元素。
2.7 front()和back():通過front()可以獲得list容器中的頭部元素,通過back()可以獲得list容器的最後乙個元素。但是有一點要注意,就是list中元素是空的時候,這時候呼叫front()和back()會發生什麼呢?實際上會發生不能正常讀取資料的情況,但是這並不報錯,那我們程式設計序時就要注意了,個人覺得在使用之前最好先呼叫empty()函式判斷list是否為空。
2.8 pop_back和pop_front():通過
刪除最後乙個元素,通過pop_front()刪除第乙個元素;序列必須不為空,如果當list為空的時候呼叫pop_back()和pop_front()會使程式崩掉。
2.9 assign():具體和vector中的操作類似,也是有兩種情況,第一種是:l1.assign(n,val)將 l1中元素變為n個t(val)。第二種情況是:l1.assign(l2.begin(),l2.end())將l2中的從l2.begin()到l2.end()之間的數值賦值給l1。
2.10 swap():交換兩個鍊錶(兩個過載),乙個是
l1.swap(l2
); 另外乙個是
swap(l1,l2),都可能完成連個鍊錶的交換。
2.11 reverse():通過reverse()完成list的逆置。
2.12 merge():合併兩個鍊錶並使之預設公升序(也可改),l1
.merge(l2,greater()); 呼叫結束後l2變為空,l1中元素包含原來l1 和 l2中的元素,並且排好序,公升序。其實預設是公升序,greater()可以省略,另外greater()是可以變的,也可以不按公升序排列。
看一下下面的程式:
1 #include 2 #include 3執行結果:4using
namespace
std;56
intmain()
719 cout
20if
(l2.empty())
2124 cout
25return0;
26 }
2.13 insert():在指定位置插入乙個或多個元素(三個過載):
l1.insert(l1.begin(),100); 在l1的開始位置插入100。
l1.insert(l1.begin(),2,200); 在l1的開始位置插入2個100。
l1.insert(l1.begin(),l2.begin(),l2.end());在l1的開始位置插入l2的從開始到結束的所有位置的元素。
2.14 erase():刪除乙個元素或乙個區域的元素(兩個過載)
l1.erase(l1.begin()); 將l1的第乙個元素刪除。
l1.erase(l1.begin(),l1.end()); 將l1的從begin()到end()之間的元素刪除。
c 容器(list學習總結)
list是乙個線性雙向鍊錶結構,它的資料由若干個節點構成,每乙個節點都包括乙個資訊塊 即實際儲存的資料 乙個前驅指標和乙個後驅指標。它無需分配指定的記憶體大小且可以任意伸縮,這是因為它儲存在非連續的記憶體空間中,並且由指標將有序的元素鏈結起來。由於其結構的原因,list 隨機檢索的效能非常的不好,因...
初級總結 容器1 List介面
扯了幾個簡單的程式,現在要進入初級的難點之一 容器。容器知識點包括 乙個圖,三個知識點 泛型,遍歷,比較器 六個介面,以及九個常用類。重點要把握 增加,刪除,修改,獲取以及遍歷。這對後面學習jdbc,db的crud有很大的作用。1 list介面 有序內容可重複 它有三個重要的子類 arraylist...
list容器和forward list容器
list就是乙個雙向鍊錶,只支援雙向順序訪問,並且還是乙個環形鍊錶。因此list只需要乙個指標就可以完整表現整個鍊錶。如果讓指標node指向刻意置於尾端的乙個空白節點,node便能符合stl對於前閉後開的要求,成為last迭代器。相較於vector的連續線性空間,list就顯得複雜許多,他的好處是每...