List的基本概念
List内部实现为一个doubly linked list(双向链表)管理元素。
使用List时必须要包括头文件<list>
#include<list>
其中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不同
List即不提供subscript(下标)操作符,也不提供at()。
List并未提供容量,空间重新分配等操作函数,因为每个元素都有自己的内存,在元素被删除前一直有效。
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: