基于C++11的List容器分析

List的基本概念

  1. List内部实现为一个doubly linked list(双向链表)管理元素。

  1. 使用List时必须要包括头文件<list>

#include<list>
  1. 其中list类型定义于namespace std中,是个class template

namespace std{
  template<typename T,typename Allocator =allocator<T>>
      class list;
}

list的第一个参数可以是任何类型T,第二个template实参可有可无,用来指定内存模型。默认的内存模型是C++标准库所提供的allocator.

List的能力

List的内部结构和array,vector或deque都不相同。List自身提供了两个pointer,用来指向第一个和最末的一个元素。每个元素都要pointer指向前一个和下一个元素(双链表的节点)。如果想要安插新元素,只需操作对应的pointer即可。

在以下几个方面,list和array,vector,deque不同

1.List不支持随机访问。这意味着你访问任意元素的时间都是很缓慢的行为。但第一个和末尾的元素访问的速度很快。

2.任何位置上的删除和安插元素的速度都很快。始终都在常量时间完成,因为无需移动任何其他元素。

3.安插和删除的动作并不会造成指向其他元素的各个pointer,reference和iterator失效。

4.List对于异常处理的方式是:要么操作成功,要么什么都不发生。

List所提供的成员函数反应出它和array,vector,deque不同

  1. List即不提供subscript(下标)操作符,也不提供at()。

  1. List并未提供容量,空间重新分配等操作函数,因为每个元素都有自己的内存,在元素被删除前一直有效。

  1. List提供不少特殊成员函数,专门用于移动和移除元素。较之同名的STL算法,这些函数执行起来更为迅速,因为他们无需复制或搬移元素,只需调整若干pointer即可。

List的操作

创建,复制和销毁(Creat,Copy,and Destroy)

list<T>c            //default构造函数,产生一个空的list
list<T>c(c2)        //copy构造函数,建立c2的同型list并成为c2的一份拷贝(所有元素被拷贝)
list<T>c=c2         //copy构造函数,建立c2的同型list并成为c2的一份拷贝(所有元素被拷贝)
list<T>c(rv)        //move构造函数,建立一个新的list,取rv的内容
list<T>c=rv         //move构造函数,建立一个新的list,取rv的内容
list<T>c(n)         //利用元素的default构造函数生成一个大小为n的list
list<T>c(n,elem)    //生成一个大小为n的list,每个元素的值都是elem
list<T>c(beg,end)   //生成一个list,以区间[begin,end)作为元素初值
list<T>c(initlist)  //生成一个list,以初始值列表的元素为初值
list<T>c=initlist   //生成一个list,以初始值列表的元素为初值
c.~list()           //销毁所有元素,释放内存

非更易型操作(Nonmodifying Operation)

c.empty() //返回是否容器为空(相当于size()==0但也许较快)
c.size()  //返回元素的数量
c.max_size() //返回元素个数之最大可能量
c1==c2   //返回c1是否等于c2
c1!=c2   //返回c1是否不等于c2
c1>c2    //返回c1是否大于c2
c1<c2    //返回c1是否小于c2
c1>=c2   //返回c1是否大等于c2
c1<=c2   //返回c1是否小等于c2

元素访问(Element Access)

赋值操作

c=c2              //将c2的全部元素赋值给c
c=rv              //将rv的所有元素都已move assign的方式给予c
c=initlist        //将初始值列表的所有元素赋值给c
c.assign(n,elem)  //赋值给list,n个元素的值都是elem值
c.assign(beg,end) //将区间[begin,end)的元素赋值给list
c.assign(initlist)//将初始值列表的元素赋值给list
c1.swap(c2)       //置换c1和c2的值
swap(c1,c2)       //置换c1和c2的值

访问操作

c.front()    //返回第一元素(不执行范围检查)
c.back()     //返回最末元素(同上)

一如既往,这些操作并不检查容器是否为空。为了防止未定义的行为,在调用前要检查容器是否为空

迭代器的相关函数(Iterator Function)

由于list的迭代器是双向迭代器,因此不能

使用随机访问的STL算法,特别是排序类算法,但是你可以使用list的特殊成员函数sort()取代之

c.begin()      //返回一个指向首处 bidirectional iterator
c.cbegin()     //返回一个const bidirectional iterator
c.end()        //返回一个指向末尾下一个位置的 bidirectional iterator
c.cend()       //返回一个指向末尾下一个位置的const bidirectional iterator
c.rbegin()     //返回一个reverse bidirectional iterator,指向末尾的下一个位置
c.rend()       //返回一个reverse bidirectional iterator,指向首处的位置
c.crend()      //返回一个const reverse bidirectional iterator,指向首处的位置
c.crbegin()    //返回一个const reverse bidirectional iterator,指向末尾的下一个位置

元素的安插和移除(Inserting and Removing)

c.push_back(elem)//附加elem的拷贝于容器的末尾
c.pop_back()//移除最后一个元素,但是不返回它
c.push_front()//附加elem的拷贝于容器的首处
c.pop_front()//移除第一个元素,但是不返回它
c.insert(pos,elem)//在pos的前方插入elem的一个拷贝,并且返回新元素的位置
c.insert(pos,n,elem)//在pos的前方插入elem的n个拷贝,并且返回第一个新元素的位置
c.insert(pos,beg,end)//在pos的前方插入elem的一个拷贝,并且返回第一个新元素的位置
c.insert(pos,initlist)//在pos的前方插入elem的一个拷贝,并且返回第一个新元素的位置
c.emplace(pos,args...)//在pos的前方插入以args作为初值的元素,并且返回新元素的位置
c.emplace_back(args...)//末尾插入以args作为初值的元素,并且返回新元素的位置
c.emplace_front(args...)//首处插入以args作为初值的元素,并且返回新元素的位置
c.erase(pos)//移除pos位置上的元素,并返回下一元素的位置
c.erase(beg,end)//移除[begin,end)区间内的元素,并返回下一元素的位置
c.remove(val)//移除所有值为val的元素
c.remove_if(op)//移除所有造成op(elem)结果为true的元素
c.resize(num)//将元素数量改为num,如果size()变大,则以元素default构造函数完成初始化
c.resize(num,elem)//将元素数量改为num,如果size()变大,则以elem的拷贝作为新元素的值
c.clear()//移除所有元素,将容器清空

相对于deque新增了remove和remove_if函数,相比于STL中的remove算法,其速度更快,因为它只对内部的pointer操作,不改变元素,所以当你面对list,你应该调用成员函数remove而不是STL算法

remove_if()函数的演示:

coll.remove_if([](int i){return i%2==0});

这里用lambda作为op判断“传入的元素是否是偶数”

List的特殊更易型操作(Special Modifying Operator)

c.unique()             //如果存在若干相邻而数值相同的元素,就移除重复元素,只留一个
c.unique()             //如果存在若干相邻都使op()的结果为true的元素,就移除重复元素,只留一个
c.splice(pos,c2)       //将c2的所有元素转移到c之内,迭代器pos之前
c.splice(pos,c2,c2pos) //将c2的c2pos所指元素转移到c内迭代器pos所指位置(c和c2可相同)
c.splice(pos,c2,c2beg,c2end) //将c2的c2beg和c2end区间内元素转移到c内迭代器pos之前位置(c和c2可相同)
c.sort()          //以元素的operator <为准则对所有元素排序
c.sort(op)        //以元素的op()为准则对所有元素排序
c.merge(c2)       //假设c和c2容器都包含op()准则下的已排序元素,将c2的全部元素转移到c,并保证合并后的list仍为以排序
c.merge(c2,op)    //假设c和c2容器都包含已排序元素,将c2的全部元素转移到c,并保证合并后的list在op()准则下仍为已排序
c.reverse()       //将所有元素反序

异常处理(Exception Handling)

在所有的STL容器中,list对于异常安全性提供了最佳支持。几乎所有的操作要么成功要么失败。唯一不提供如此保证的是赋值运算和成员函数sort(),不过他们也有基本保证:异常发生时不会泄露资源。merge(),remove(),remove_if()和unique()提供的保证是有前提的,那就是元素间的比较动作(operator ==和判断式)不抛出异常。

List使用实例

#include<list>
#include<iostream>
#include<algorithm>
#include<iterator>
using namespace std;

void printLists(const list<int>&l1,const list<int>&l2){
      cout<<"list1: ";
      copy(l1.cbegin(),l1.cend(),ostream_iterator(cout," "));
      cout<<endl<<"list2: ";
      copy(l2.cbegin(),l2.cend(),ostream_iterator(cout," "));
      cout<<endl<<endl;
}

int main(){
      list<int>list1,list2;

      for(int i=0;i<6;++i){
         list1.push_back(i);
         list2.push_front(i);
      }  
      printLists(list1,list2);

      list2.splice(find(list2.begin(),list2.end(),3),list1);
      printLists(list1,list2);

      list2.splice(list2.end(),list2,list2.begin());
      printLists(list1,list2);

      list2.sort();
      list1=list2;
      list2.unique();
      printLists(list1,list2);

      list1.merge(list2);
      printLists(list1,list2);
}      

输出结果:

list1: 0 1 2 3 4 5
list2: 5 4 3 2 1 0

list1:
list2: 5 4 0 1 2 3 4 5 3 2 1 0

list1:
list2: 4 0 1 2 3 4 5 3 2 1 0 5

list1: 0 0 1 1 2 2 3 3 4 4 5 5
list2: 0 1 2 3 4 5

list1: 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5
list2:
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Reol520

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值