1.關於list容器
list是一種序列式容器。list容器完成的功能實際上和數據結構中的雙向鏈表是極其相似的,list中的數據元素是通過鏈表指針串連成邏輯意義上的線性表,也就是list也具有鏈表的主要優點,即:在鏈表的任一位置進行元素的插入、刪除操作都是快速的。list的實現大概是這樣的:list的每個節點有三個域:前驅元素指針域、數據域和后繼元素指針域。前驅元素指針域保存了前驅元素的首地址;數據域則是本節點的數據;后繼元素指針域則保存了后繼元素的首地址。其實,list和循環鏈表也有相似的地方,即:頭節點的前驅元素指針域保存的是鏈表中尾元素的首地址,list的尾節點的后繼元素指針域則保存了頭節點的首地址,這樣,list實際上就構成了一個雙向循環鏈。由於list元素節點並不要求在一段連續的內存中,顯然在list中是不支持快速隨機存取的,因此對於迭代器,只能通過“++”或“--”操作將迭代器移動到后繼/前驅節點元素處。而不能對迭代器進行+n或-n的操作,這點,是與vector等不同的地方。
我想把三個常用的序列式放在一起對比一下是有必要的:
vector : vector和built-in數組類似,擁有一段連續的內存空間,能非常好的支持隨即存取,即[]操作符,但由於它的內存空間是連續的,所以在中間進行插入和刪除會造成內存塊的拷貝,另外,當插入較多的元素后,預留內存空間可能不夠,需要重新申請一塊足夠大的內存並把原來的數據拷貝到新的內存空間。這些影響了vector的效率,但是實際上用的最多的還是vector容器,建議大多數時候使用vector效率一般是不錯的。vector的用法解析可以參考本人的另一篇隨筆:http://www.cnblogs.com/BeyondAnyTime/archive/2012/08/08/2627666.html
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<int>()); 調用結束后l2變為空,l1中元素包含原來l1 和 l2中的元素,並且排好序,升序。其實默認是升序,greater<int>()可以省略,另外greater<int>()是可以變的,也可以不按升序排列。
看一下下面的程序:

1 #include <iostream> 2 #include <list> 3 4 using namespace std; 5 6 int main() 7 { 8 list<int> l1; 9 list<int> l2(2,0); 10 list<int>::iterator iter; 11 l1.push_back(1); 12 l1.push_back(2); 13 l2.push_back(3); 14 l1.merge(l2,greater<int>());//合並后升序排列,實際上默認就是升序 15 for(iter = l1.begin() ; iter != l1.end() ; iter++) 16 { 17 cout<<*iter<<" "; 18 } 19 cout<<endl<<endl; 20 if(l2.empty()) 21 { 22 cout<<"l2 變為空 !!"; 23 } 24 cout<<endl<<endl; 25 return 0; 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()之間的元素刪除。
學習中的一點總結,歡迎拍磚哦^^