STL中list的容器使用介绍

来源:互联网 发布:子域名扫描工具 编辑:程序博客网 时间:2024/05/22 00:05

STLlist容器使用介绍

 

       STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件。STL现在是C++的一部分,因此不用额外安装什么。它被内建在你的编译器之内。因为STLlist是一个简单的容器,所以我打算从它开始介绍STL如何使用。如果你懂得了这个概念,其他的就都没有问题了。另外,list容器是相当简单的,我们会看到这一点。 

      STL容器可以保存对象,内建对象和类对象。它们会安全的保存对象,并定义我们能够操作的这个对象的接口。放在蛋架上的鸡蛋不会滚到桌上。它们很安全。因此,在STL容器中的对象也很安全。

     STL算法是标准算法,我们可以把它们应用在那些容器中的对象上。这些算法都有很著名的执行特性。它们可以给对象排序,删除它们,给它们记数,比较,找出特殊的对象,把它们合并到另一个容器中,以及执行其他有用的操作。 
     STL iterator就象是容器中指向对象的指针STL的算法使用iterator在容器上进行操作。Iterator设置算法的边界 ,容器的长度,和其他一些事情。举个例子,有些iterator仅让算法读元素,有一些让算法写元素,有一些则两者都行。 Iterator也决定在容器中处理的方向。
你可以通过调用容器的成员函数begin()来得到一个指向一个容器起始位置iterator。你可以调用一个容器的 end() 函数来得到过去的最后一个值(就是处理停在那的那个值)。 

这就是STL所有的东西,容器、算法、和允许算法工作在容器中的元素上的iterator。 算法以合适、标准的方法操作对象,并可通过iterator得到容器精确的长度。一旦做了这些,它们就在也不会跑出边界。 还有一些其他的对这些核心组件类型有功能性增强的组件,例如函数对象。我们将会看到有关这些的例子,现在 ,我们先来看一看STLlist

 

STL中的list就是一双向链表, list将元素按顺序储存在链表中与 向量(vectors)相比它允许快速的插入和删除,但是随机访问却比较慢

 

文中所用到两个list对象list_c1, list_c2分别有元素list_c1(10,20,30)  list_c2(40,50,60)。还有一个list<int>::iterator citer用来指向list_c1或list_c2元素。

 

list对象的声明构造()

 

A. list<int> list_c0;               //空链表

B. list<int> list_c1(3);             //建一个含三个默认值是0的元素的链表

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

D. list<int> list_c4(list_c2);         //建一个list_c2的copy链表 

E. list<int> list_c5(list_c1.begin(),list_c1.end());  //list_c5list_c1一个区域的元素[_First, _Last)。 

 

如何定义一个list对象

#include <list>

int main (void)

{

  list<char > cList;  //声明了list<char>模板类 的一个实例

}

 

1. assign() 给list值,有两个重载:

 

list_c1.assign(++list_c2.begin(), list_c2.end())   //list_c1现在为(50,60)

list_c1.assing(7,4)                                              //list_c1中现在为74,list_c1(4,4,4,4,4,4,4)

 

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

 

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

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

 

3. begin()返回第一个元素的指针(iterator)

 

list<int>::iterator citer=list_c1.begin();     // *citer=10

list<int>::const_iterator cciter=list_c1.begin();  //*cciter=10且为const

 

4. clear()删除所有元素

 

list_c1.clear();    //list_c1为空  list_c1.size为0;

 

5. empty()判断是否链表为空

 

bool B=list_c1.empty();  //list_c1为空B=true;否则B=false;

 

6. end()返回最后一个元素的下一位置的指针(list为空时end()=begin())

 

list<int>::iterator citer=list_c1.end(); //*(--citer)=30; 

begin()返回一个常指针,不能修改其中元素。

 

7. erase()删除一个元素或一个区域的元素(两个重载)

 

list_c1.erase(list_c1.begin());                             // list_c1现为(20,30); 

list_c1.erase(++list_c1.begin(),list_c1.end());    //list_c1现为(10);

 

erase的作用是,使作为参数的迭代器失效,并返回指向该迭代器下一参数的迭代器。

如下:

list<DotSource> ParticleSystem;

list<DotSource>::iterator pointer;

if(pointer->dead == true)
{
pointer = ParticleSystem.erase(pointer);
}

 

有一段关于错误使用erase的程序

#include<stdio.h>
#include<list>
using namespace std;
int main()
{
std::list<int>test_list;
std::list<int>::iterator test_list_it;

test_list.push_back(1);

test_list_it = test_list.begin();
for(;test_list_it != test_list.end();test_list_it++)

{
test_list.erase(test_list_it);
}
}

问题:该程序不能跳出循环

原因:test_list.erase(test_list_it);每次做erase时都有可能使迭代器失效,test_list_it++就发生错误了。可以参见effective stl一书。所有容器做erase操作时都有可能使迭代器失效。

 

改为:

for(;test_list_it != test_list.end();)
{
test_list.erase(test_list_it++);
}

or

for(;test_list_it != test_list.end();)
{
std::list<int>::iterator iter_e=test_list_it++;
test_list.erase(iter_e);
}

注意:

for(; test_list_it != test_list.end(); test_list_it++;)
{
std::list<int>::iterator iter_e=test_list_it;
test_list.erase(iter_e);
}
这样任然是错误的,原因是:iter_e=test_list_it 是指针值的复制,它俩其实指向同一个位置,所以iter_e失效那么test_list_it也会失效,所以test_list_it++就会有问题
如果是:

for( ; test_list_it != test_list.end() ; )
{
std::list<int>::iterator iter_e=test_list_it++;
test_list.erase(iter_e);
}
则没有问题。

 

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

 

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

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

 

9. insert()在指定位置插入一个或多个元素(三个重载)

 

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

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

list_c1.insert(++list_c1.begin(),list_c2.begin(),--list_c2.end());     //list_c1(10,40,50,20,30);

 

10. max_size()返回链表最大可能长度(size_type就是int)

 

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

 

11. merge()合并两个链表并使之默认升序(也可改)

 

list_c2.merge(list_c1);   //list_c1现为空;list_c2现为list_c2(10,20,30,40,50,60)

 

list_c2.merge(list_c1,greater<int>()); //同上,但list_c2现为降序

 

12. pop_back()删除链表尾的一个元素

 

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

 

13. pop_front()删除链表头的一元素

 

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

 

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

 

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

 

15. push_front()增加一元素到链表头

 

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

 

16. rbegin()返回链表最后一元素的后向指针(reverse_iterator or const)

 

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

 

17. rend()返回链表第一元素的下一位置的后向指针

 

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

 

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

 

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

 

for (list<int>::iterator i = list_c1.begin();  i != list_c1.end(); ) {
      printf("remove %d \n", *i);
      list_c1.remove(*i++);
}

 

19. remove_if()删除条件满足的元素(会遍历一遍链表)

 

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

                                                       //is_odd自己写(表奇数)

 

20. resize()重新定义链表长度(两重载)

 

list_c1.resize(4)                             //list_c1(10,20,30,0)用默认值填补

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

 

21. reverse()反转链表:

 

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

 

22. size()返回链表中元素个数

 

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

 

23. sort()对链表排序,默认升序(可自定义)

 

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

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

 

24. splice()对两个链表进行结合(三个重载)

 

list_c1.splice(++list_c1.begin(),list_c2);                                        //list_c1(10,40,50,60,20,30) list_c2为空 全合并

list_c1.splice(++list_c1.begin(),list_c2,++list_c2.begin());            //list_c1(10,50,20,30) ; list_c2(40,60) 指定元素合并

list_c1.splice(++list_c1.begin(),list_c2,++list_c2.begin(),list_c2.end());         //list_c1(10,50,60,20,30); list_c2(40) 指定范围合并

 

25. swap()交换两个链表(两个重载)

 

list_c1.swap(list_c2);             //list_c1(40,50,60);

swap(list_c1,list_c2);  //list_c1(40,50,60)

 

26. unique()删除相邻重复元素(断言已经排序,因为它不会删除不相邻的相同元素)

 

list_c1.unique();  //假设list_c1开始(-10,10,10,20,20,-10)则之后为list_c1(-10,10,20,-10)

list_c1.unique(mypred); //自定义谓词

 

27、用list< char >::iterator得到指向list的指针 list< char>::iterator cIterator;

for(cIterator = cList.Begin(); cIterator != cList.end(); cIterator++)

{

printf(“%c”, *cIterator);

输出list中的所有对象 说明:cList.Begin()cList.end()函数返回指向list< char >::iterator的指针,由于list采用链表结构,因此它不支持随机存取,因此不能用cList.begin()+3来指向list中的第四个对象,vectordeque支持随机存取。

 

28、用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时返回truefalse。它们根据这个来判定这个函数。举个例子会 说的更清楚些。count_if()通过传递一个函数对象来作出比count()更加复杂的评估以确定一个对象是否应该被记数。

 

29、使用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的指针。

 

//find操作查找等于10的元素,并返回指向该元素的迭代器,如果没有找到,返回指向集合最后一个元素的迭代器
int iSearchValue = 10;
list<int>::iterator iLocation = find(ilist.begin(), ilist.end(), iSearchValue);      if (iLocation != ilist.end())  {      cout << "value: " <<*iLocation;
    cout << "找到元素 10" << endl;  }  


30、使用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的指针。

 

31、使用list的成员函数sort()排序 

cList.sort();    //默认升序排序

 

32、使用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指出的位置以前。

 

32、如何在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’);

 

 

0 0