C++ list 類學習筆記

雙向循環鏈表list

        list是雙向循環鏈表,,每一個元素都知道前面一個元素和後面一個元素。在STL中,list和vector一樣,是兩個常被使用的容器。和vector不一樣的是,list不支持對元素的任意存取。list中提供的成員函數與vector類似,不過list提供對錶首元素的操作push_front、pop_front,這是vector不具備的。和vector另一點不同的是,list的迭代器不會存在失效的情況,他不像vector會保留備份空間,在超過容量額度時重新全部分配內存,導致迭代器失效;list沒有備份空間的概念,出入一個元素就申請一個元素的空間,所以它的迭代器不會失效。還是舉《C++之vector》中的例子:

int data[6]={3,5,7,9,2,4};  
list<int> lidata(data, data+6);  
lidata.push_back(6);  
...

list初始化時,申請的空間大小爲6,存放下了data中的6個元素,當向lidata插入第7個元素“6”時,list申請新的節點單元,插入到list鏈表中,數據存放結構如圖1所示:

 

圖1 list的存儲結構

        list每次增加一個元素,不存在重新申請內存的情況,它的成本是恆定的。而vector每當增加關鍵元素的時候,都需要重新申請新的更大的內存空間,會調用元素的自身的複製構造函數,存在構造成本。在銷燬舊內存的時候,會調用析構函數,存在析構成本。所以在存儲複雜類型和大量元素的情況下,list比vector更有優勢! 

    List是一個雙向鏈表,雙鏈表既可以向前又向後鏈接他的元素。

    List將元素按順序儲存在鏈表中. 與 向量(vector)相比, 它允許快速的插入和刪除,但是隨機訪問卻比較慢。

assign() 給list賦值 

back() 返回最後一個元素 

begin() 返回指向第一個元素的迭代器 

clear() 刪除所有元素 

empty() 如果list是空的則返回true 

end() 返回末尾的迭代器 

erase() 刪除一個元素 

front() 返回第一個元素 

get_allocator() 返回list的配置器 

insert() 插入一個元素到list中 

max_size() 返回list能容納的最大元素數量 

merge() 合併兩個list 

pop_back() 刪除最後一個元素 

pop_front() 刪除第一個元素 

push_back() 在list的末尾添加一個元素 

push_front() 在list的頭部添加一個元素 

rbegin() 返回指向第一個元素的逆向迭代器 

remove() 從list刪除元素 

remove_if() 按指定條件刪除元素 

rend() 指向list末尾的逆向迭代器 

resize() 改變list的大小 

reverse() 把list的元素倒轉 

size() 返回list中的元素個數 

sort() 給list排序 

splice() 合併兩個list 

swap() 交換兩個list 

unique() 刪除list中重複的元素


 List使用實例1

#include <iostream>

#include <list>

#include <numeric>

#include <algorithm>

using namespace std;


//創建一個list容器的實例LISTINT

typedef list<int> LISTINT;

//創建一個list容器的實例LISTCHAR

typedef list<char> LISTCHAR;


int main(int argc, char *argv[])

{

//--------------------------

//用list容器處理整型數據

//--------------------------

//用LISTINT創建一個名爲listOne的list對象

LISTINT listOne;

//聲明i爲迭代器

LISTINT::iterator i;


//從前面向listOne容器中添加數據

listOne.push_front (2);

listOne.push_front (1);


//從後面向listOne容器中添加數據

listOne.push_back (3);

listOne.push_back (4);


//從前向後顯示listOne中的數據

cout<<"listOne.begin()--- listOne.end():"<<endl;

for (i = listOne.begin(); i != listOne.end(); ++i)

cout << *i << " ";

cout << endl;


//從後向後顯示listOne中的數據

LISTINT::reverse_iterator ir;

cout<<"listOne.rbegin()---listOne.rend():"<<endl;

for (ir =listOne.rbegin(); ir!=listOne.rend();ir++) {

cout << *ir << " ";

}

cout << endl;


//使用STL的accumulate(累加)算法

int result = accumulate(listOne.begin(), listOne.end(),0);

cout<<"Sum="<<result<<endl;

cout<<"------------------"<<endl;


//--------------------------

//用list容器處理字符型數據

//--------------------------


//用LISTCHAR創建一個名爲listOne的list對象

LISTCHAR listTwo;

//聲明i爲迭代器

LISTCHAR::iterator j;


//從前面向listTwo容器中添加數據

listTwo.push_front ('A');

listTwo.push_front ('B');


//從後面向listTwo容器中添加數據

listTwo.push_back ('x');

listTwo.push_back ('y');


//從前向後顯示listTwo中的數據

cout<<"listTwo.begin()---listTwo.end():"<<endl;

for (j = listTwo.begin(); j != listTwo.end(); ++j)

cout << char(*j) << " ";

cout << endl;


//使用STL的max_element算法求listTwo中的最大元素並顯示

j=max_element(listTwo.begin(),listTwo.end());

cout << "The maximum element in listTwo is: "<<char(*j)<<endl;

return 0;

}

 List使用實例2

list: Linked list of variables, struct or objects. Insert/remove anywhere.

Two examples are given:

  1. The first STL example is for data type int
  2. The second for a list of class instances.
They are used to show a simple example and a more complex real world application.

1. Lets start with a simple example of a program using STL for a linked list:  

// Simple example uses type int

#include <iostream>

#include <list>

using namespace std;


int main()

{

   list<int> L;

   L.push_back(0);              // Insert a new element at the end

   L.push_front(0);             // Insert a new element at the beginning

   L.insert(++L.begin(),2);     // Insert "2" before position of first argument

                                            // (Place before second argument)

   L.push_back(5);

   L.push_back(6);

   list<int>::iterator i;

   for(i=L.begin(); i != L.end(); ++i) cout << *i << " ";

   cout << endl;

   return 0;

}

Compile: g++ example1.cpp

Run: ./a.out

Output: 0 2 0 5 6

2. The STL tutorials and texts seem to give simple examples which do not apply to the real world. The following example is for a doubly linked list. Since we are using a class and we are not using defined built-in C++ types we have included the following:

  • To make this example more complete, a copy constructor has been included although the compiler will generate a member-wise one automatically if needed. This has the same functionality as the assignment operator (=).
  • The assignment (=) operator must be specified so that sort routines can assign a new order to the members of the list.
  • The "less than" (<) operator must be specified so that sort routines can determine if one class instance is "less than" another.
  • The "equals to" (==) operator must be specified so that sort routines can determine if one class instance is "equals to" another. 

// Standard Template Library example using a class.

#include <iostream>

#include <list>

using namespace std;

// The List STL template requires overloading operators =, == and <.

//vc2005調試沒有錯(紅色字體部分可去掉)、可用vc6.0卻報錯了“'operator <<' is ambiguous”(vc6.0的加上紅色字體部分)

class AAA;
ostream &operator<<(ostream &output, const AAA &aaa);

class AAA

{

   friend ostream &operator<<(ostream &, const AAA &);

   public:

      int x;

      int y;

      float z;


      AAA();

      AAA(const AAA &);

      ~AAA(){};

      AAA &operator=(const AAA &rhs);

      int operator==(const AAA &rhs) const;

      int operator<(const AAA &rhs) const;

};

AAA::AAA()   // Constructor

{

   x = 0;

   y = 0;

   z = 0;

}

AAA::AAA(const AAA &copyin)   // Copy constructor to handle pass by value.

{                             

   x = copyin.x;

   y = copyin.y;

   z = copyin.z;

}

ostream &operator<<(ostream &output, const AAA &aaa)

{

   output << aaa.x << ' ' << aaa.y << ' ' << aaa.z << endl;

   return output;

}

AAA& AAA::operator=(const AAA &rhs)

{

   this->x = rhs.x;

   this->y = rhs.y;

   this->z = rhs.z;

   return *this;

}

int AAA::operator==(const AAA &rhs) const

{

   if( this->x != rhs.x) return 0;

   if( this->y != rhs.y) return 0;

   if( this->z != rhs.z) return 0;

   return 1;

}

// This function is required for built-in STL list functions like sort

int AAA::operator<(const AAA &rhs) const

{

   if( this->x == rhs.x && this->y == rhs.y && this->z < rhs.z) return 1;

   if( this->x == rhs.x && this->y < rhs.y) return 1;

   if( this->x < rhs.x ) return 1;

   return 0;

}

int main()

{

   list<AAA> L;

   AAA Ablob ;

   Ablob.x=7;

   Ablob.y=2;

   Ablob.z=4.2355;

   L.push_back(Ablob);  // Insert a new element at the end

   Ablob.x=5;

   L.push_back(Ablob);  // Object passed by value. Uses default member-wise

                        // copy constructor

   Ablob.z=3.2355;

   L.push_back(Ablob); 


   Ablob.x=3;

   Ablob.y=7;

   Ablob.z=7.2355;

   L.push_back(Ablob); 


   list<AAA>::iterator i;


   for(i=L.begin(); i != L.end(); ++i) cout << (*i).x << " "; // print member

   cout << endl;      


   for(i=L.begin(); i != L.end(); ++i) cout << *i << " "; // print with overloaded operator

   cout << endl;


   cout << "Sorted: " << endl;

   L.sort();

   for(i=L.begin(); i != L.end(); ++i) cout << *i << " "; // print with overloaded operator

   cout << endl;

   return 0;

}

Output:

7 5 5 3 
7 2 4.2355
 5 2 4.2355
 5 2 3.2355
 3 7 7.2355
 
Sorted:
3 7 7.2355
 5 2 3.2355
 5 2 4.2355
 7 2 4.2355



STL中list的使用:

STL中的list就是一雙向鏈表,可高效地進行插入刪除元素。現總結一下它的操作。

文中所用到兩個list對象c1,c2分別有元素c1(10,20,30)  c2(40,50,60)。還有一個list<int>::iterator citer用來指向c1或c2元素。

list對象的聲明構造():

A.      list<int>c0;                 //空鏈表

B.      list<int>c1(3);             //建一個含三個默認值是0的元素的鏈表

C.      list<int>c2(5,2);            //建一個含五個元素的鏈表,值都是2

D.      list<int>c4(c2);             //建一個c2的copy鏈表

E.       list<int>c5(c1.begin(),c1.end());  

//c5含c1一個區域的元素[_First, _Last)。

 

1.       assign()分配值,有兩個重載:

c1.assign(++c2.begin(), c2.end()) //c1現在爲(50,60)。

c1.assing(7,4)  //c1中現在爲7個4,c1(4,4,4,4,4,4,4)。

2.       back()返回最後一元素的引用:

int i=c1.back();  //i=30

const int i=c2.back();  //i=60且不可修改

3.       begin()返回第一個元素的指針(iterator)

citer=c1.begin();    // *citer=10

list<int>::const_iterator cciter=c1.begin(); //*cciter=10且爲const。

4.       clear()刪除所有元素

c1.clear();   //c1爲空  c1.size爲0;

5.       empty()判斷是否鏈表爲空

bool B=c1.empty(); //若c1爲空B=true;否則B=false;

6.       end()返回最後一個元素的下一位置的指針(list爲空時end()=begin())

citer=c1.end(); //*(--citer)=30;

同begin()返回一個常指針,不能修改其中元素。

7.       erase()刪除一個元素或一個區域的元素(兩個重載)

c1.erase(c1.begin()); // c1現爲(20,30);

c1.erase(++c1.begin(),c1.end()); // c1現爲(10);

8.       front() 返回第一個元素的引用:

int i=c1.front(); //i=10;

const int i=c1.front(); //i=10且不可修改。

9.       insert()在指定位置插入一個或多個元素(三個重載):

c1.insert(++c1.begin(),100);   //c1(10,100,20,30)

c1.insert(c1.begin(),2,200);  //c1(200,200,20,30);

c1.insert(++c1.begin(),c2.begin(),--c2.end());

 //c1(10,40,50,20,30);

10.    max_size()返回鏈表最大可能長度(size_type就是int型):

list<int>::size_type i=c1.max_size();  //i=1073741823

11.    merge()合併兩個鏈表並使之默認升序(也可改):

c2.merge(c1);   //c1現爲空;c2現爲c2(10,20,30,40,50,60)

c2.merge(c1,greater<int>()); //同上,但c2現爲降序

12.    pop_back()刪除鏈表尾的一個元素

c1.pop_back()  //c1(10,20);

13.    pop_front()刪除鏈表頭的一元素

c1.pop_front() //c1(20,30)

14.    push_back()增加一元素到鏈表尾

c1.push_back(100) //c1(10,20,30,100)

15.    push_front()增加一元素到鏈表頭

c1.push_front(100) //c1(100,10,20,30)

16.    rbegin()返回鏈表最後一元素的後向指針(reverse_iterator or const)

list<int>::reverse_iterator riter=c1.rbegin(); //*riter=30

17.    rend()返回鏈表第一元素的下一位置的後向指針

list<int>::reverse_iterator riter=c1.rend(); // *(--riter)=10

18.    remove()刪除鏈表中匹配值的元素(匹配元素全部刪除)

c1.remove(10);     //c1(20,30)

19.    remove_if()刪除條件滿足的元素(會遍歷一遍鏈表)

c1.remove_if( is_odd<int> () ); //c1(10,20,30) 

//is_odd自己寫(表奇數) 

20.    resize()重新定義鏈表長度(兩重載):

c1.resize(4)  //c1(10,20,30,0)用默認值填補

c1.resize(4,100) //c1(10,20,30,100)用指定值填補

21.    reverse()反轉鏈表:

c1.reverse(); //c1(30,20,10)

22.    size()返回鏈表中元素個數

list<int>::size_type i=c1.size();  //i=3

23.    sort()對鏈表排序,默認升序(可自定義)

c1.sort();  //c1(10,20,30)

c1.sort(great<int>()); //c1(30,20,10)

24.    splice()對兩個鏈表進行結合(三個重載)

c1.splice(++c1.begin(),c2); 

//c1(10,40,50,60,20,30) c2爲空 全合併

c1.splice(++c1.begin(),c2,++c2.begin());

//c1(10,50,20,30) ; c2(40,60) 指定元素合併

c1.splice(++c1.begin(),c2,++c2.begin(),c2.end());

//c1(10,50,60,20,30); c2(40) 指定範圍合併

25.    swap()交換兩個鏈表(兩個重載)

c1.swap(c2);  //c1(40,50,60);

swap(c1,c2);  //c1(40,50,60)

26.    unique()刪除相鄰重複元素(斷言已經排序,因爲它不會刪除不相鄰的相同元素)

c1.unique(); 

//假設c1開始(-10,10,10,20,20,-10)則之後爲c1(-10,10,20,-10)

c1.unique(mypred); //自定義謂詞



list 的使用

在使用list必須包括頭文件#include <list>,
1)、如何定義一個list對象

#include <list>
int main (void)
{
 list<char > cList; //聲明瞭list<char>模板類 的一個實例
}
2)、使用list的成員函數push_back和push_front插入一個元素到list中
cList. push_back(‘a’); //把一個對象放到一個list的後面
cList. push_front (‘b’); //把一個對象放到一個list的前面
3)、使用list的成員函數empty()判斷list是否爲空
if (cList.empty())
{
 printf(“this list is empty”);
}
4)、用list< char >::iterator得到指向list的指針
list< char>::iterator charIterator;
for(cIterator = cList.Begin();cIterator != cList.end();cIterator++)
{
 printf(“%c”, *cIterator);
} //輸出list中的所有對象
說明:cList.Begin()和cList.end()函數返回指向list< char >::iterator的指針,由於list採用鏈表結構,因此它不支持隨機存取,因此不能用cList.begin()+3來指向list中的第四個對象,vector和deque支持隨機存取。

5)、用STL的通用算法count()來統計list中的元素個數
int cNum;
char ch = ’b’;
cNum = count(cList.Begin(), cList.end(), ch); //統計list中的字符b的個數
說明:在使用count()函數之前必須加入#include <algorithm> 

6)、用STL的通用算法count_if ()來統計list中的元素個數
const char c(‘c’);
class IsC
{
public:
 bool operator() ( char& ch )
 {
  return ch== c;
 }
};

int numC;
numC = count_if (cList.begin(), cList.end(),IsC());//統計c的數量;
說明:count_if() 帶一個函數對象的參數,函數對象是一個至少帶有一個operator()方法的類函數對象被約定爲STL算法調用operator時返回true或false。它們根據這個來判定這個函數。舉個例子會 說的更清楚些。count_if()通過傳遞一個函數對象來作出比count()更加複雜的評估以確定一個對象是否應該被記數。

7)、使用STL通用算法find()在list中查找對象
list<char >::iterator FindIterator;
FindIterator = find(cList.begin(), cList.end(), ‘c’);
If (FindIterator == cList.end())
{
 printf(“not find the char ‘c’!”);
}
else
{
 printf(“%c”, * FindIterator);
}
說明:如果沒有找到指定的對象,就會返回cList.end()的值,找到了就返回一個指向對象iterator的指針。

8)、使用STL通用算法find_if()在list中查找對象
const char c(‘c’);
class c
{
public:
 bool operator() ( char& ch )
 {
  return ch== c;
 }
};

list<char>::iterator FindIterator
FindIterator = find_if (cList.begin(), cList.end(),IsC());//查找字符串c;
說明:如果沒有找到指定的對象,就會返回cList.end()的值,找到了就返回一個指向對象iterator的指針。

9)、使用list的成員函數sort()排序
cList.sort();
10)、使用list的成員函數insert插入一個對象到list中
cList.insert(cLiset.end, ‘c’); ///在list末尾插入字符‘c’

char ch[3] ={‘a’, ‘b’, ‘c’};
cList.insert(cList.end, &ch[0], & ch[3] ); //插入三個字符到list中
說明:insert()函數把一個或多個元素插入到指出的iterator位置。元素將出現在 iterator指出的位置以前。

11)、如何在list中刪除元素
cList.pop_front(); //刪除第一個元素
cList.pop_back(); //刪除最後一個元素
cList. Erase(cList.begin()); //使用iterator刪除第一個元素;
cList. Erase(cList.begin(), cList.End()); //使用iterator刪除所有元素;
cList.remove(‘c’); //使用remove函數刪除指定的對象;

list<char>::iterator newEnd;
//刪除所有的’c’ ,並返回指向新的list的結尾的iterator
newEnd = cList.remove(cList.begin(), cList.end(), ‘c’);
-------------------------------------------------------------------------
原文地址:http://blog.csdn.net/whz_zb/article/details/6831817
發佈了21 篇原創文章 · 獲贊 4 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章