list容器以双向链表的方式管理它的元素,尽管c++标准没有指定list容器的具体实现,但通常其实现就是基于双向链表结构。
list容器的内部结构跟vector和deque都差别巨大,所以list容器在行为特征上跟vector和deque有明显差异:
- list容器不提供随机元素访问。如果你想访问第五个元素,那么必须先遍历前四个元素才能到达第五个元素。所以使用list容器访问任意元素是低效的。
- 在list容器的任何位置插入和删除元素的效率都是一样的,都同样高效,这基于list容器的内部结构,不需要移动其他元素,只需要维护相应的指针即可。
- 插入和删除操作不会使其他元素的引用、指针和迭代器失效。
- list容器对异常处理有着完美的支持,一个操作要么成功完成,要么对容器不产生任何影响。
跟vector和deque相比,在外部操作接口上list容器有下列区别:
- list容器既没有[]操作符,也没有at()接口,因为list容器不支持随机元素访问。
- list容器不提供对capacity和内存维护相关的接口,因为list容器中的每个元素分配自己的内存空间,当元素删除时,其对应的内存空间销毁。
- list容器额外提供了一些移动元素的接口,这些接口比相应的通用算法要高效,因为它们基于list容器的内部结构而设计,所以在需要时应该优先使用它们。
list容器跟vector、deque容器都属于序列容器(sequence containers), 所以大部分的操作接口还是类似的,像创建(create)、复制(copy)、销毁(destroy)、大小(size)、比较(compare)、赋值(assignment)、迭代器(iterator)等都基本类似。
Element Access
因为list容器不支持随机访问,所以元素访问接口只保留了front()和back(),分别用来访问第一个和最后一个元素。同样这两个接口不会检查容器是否为空,如果对一个空的list容器调用这两个接口,结果未可知。
Iterator Functions
Inserting and Removing Elements
对于插入和删除元素,list容器除了提供所有跟deque一样的接口外,还额外增补了两个删除元素的接口:remove(), remove_if():
- c.remove(val): 删除容器中所有值为val的元素。
- c.remove_if(op): 删除容器中所有使op为true的元素。
这两个函数因为根据list容器的内部结构而设计,所以比对应的通用算法要高效,所以在同等的条件下应该优先使用这两个成员函数。
Splice Functions(拼接函数)
对比vector和deque容器,list容器在内部结构上采用了链表结构,这就使得在任意位置插入和删除元素都非常便利,所以list容器额外提供了一组拼接函数,你可以使用这些成员接口在一个容器内部或者两个容器之间方便地移动元素,当然这两个容器要具备相同的类型。
- c.unique(): 删除容器中值相同位置相邻的额外元素,只保留一个元素。
- c.unique(op): 删除容器中同时满足op条件位置相邻的额外元素,只保留一个元素。
- c1.splice(pos, c2): 把容器c2中的所有元素移动到容器c1的迭代器位置pos之前。
- c1.splice(pos, c2, c2pos): 把容器c2中的c2pos位置的元素移动到容器c1的pos位置之前。(c1和c2可以是同一个容器)
- c1.splice(pos, c2, c2beg, c2end): 把容器c2中的[c2beg, c2end)范围内的所有元素移动到容器c1的pos位置之前。(c1和c2可以是同一个容器)
- c.sort(): 以操作符<(升序)来排序容器中所有元素。
- c.sort(op): 以运算子op来排序容器中所有元素。
- c1.merge(c2): 假定容器c1和c2包含的元素都已经过排序(sorted with operation < ), 该接口把c2容器中的所有元素移动到c1中并且也按照排序规则排序。
- c1.merge(c2, op): 假定容器c1和c2包含的元素都已经过排序(sorted with op), 该接口把c2容器中的所有元素移动到c1中并且也按照排序规则排序。
- c.reverse(): 反序容器中的元素次序。
list容器对异常处理有着几乎完美的支持,几乎所有的操作要么成功完成,要么保持原状。例外的操作就是赋值操作和sort()接口,不能保证这一点,但最低保证不会产生资源泄漏。另外merge(), remove(), remove_if(), unique()接口在元素比较(comparing elements)不抛出异常时保证这一点。
4.4 使用list容器的一个例子
下面我们看一个使用list容器拼接函数的例子:
执行结果如下: