与
vector
不同,
list
的底层是用
双向链表实现的,其逻辑上连续的元素并不是地址连续的。
list
每插入或删除一个元素,就配置或释放一个元素的空间,内存利用率较高。对于任意位置上元素的插入或删除操作,永远是常数时间。vector
的是O(n)
。
list的节点
template <class T>
struct ListNode {
T data;
ListNode<T> *prev;
ListNode<T> *next;
};
list的迭代器
由于list
是一个双向链表,迭代器必须具备前移、后移的能力,所以list
的迭代器属于Bidirectional Iterator
。
向list
添加元素的操作不会使原有的迭代器失效,而vector
会重新配置空间会导致原有的迭代器失效;list
的删除操作会使“指向被删除元素”的迭代器失效(引用未定义内容),而vector
的指向被删除元素的迭代器会指向被删除元素的下一个元素。
list的结构
SGI list
不仅是一个双向链表,而且还是一个环状双向链表,所以它只需要一个指针,便可表示完整的链表。
为了使list
能满足STL
对前闭后开区间的要求,环状双向链表维护了一个尾空节点。
list::end()
指向的就是尾空节点。
list
为空时,尾空节点的prev
和next
都指向自己。list
对象持有尾空节点的地址。
list的相关操作
insert
本质上,vector
和list
的插入元素操作,都会把新元素插在迭代器position所指的元素的前面,只不过在插入操作完成后,vector
的position
指向了新插入的元素,list
的position
指向原有的元素。
有如下list
:
在position
处插入新元素7
会变成这样:
vector
的话会是这样:
此外,list
支持push_front
、push_back
、pop_front
、pop_back
、erase
、clear
、remove
、unique
等操作。
transfer
list
内部提供了一个transfer
操作:将某连续范围内的元素迁移到某个特定位置之前。这个函数实现的难点在于指针的移动,它为诸如splice
、merge
、sort
等更复杂的操作奠定了基础。
list
不能使用STL
算法的sort
(只接受Random Access Iterator
),所以它自定义了一个sort
成员函数。