相对于vector的连续线性空间,list就显得复杂,好处在于,每次插入或删除一个元素,就配置或释放一个元素空间,因此list对空间的运用绝对精准,不存在任何浪费。而且,对任何位置的元素的插入或元素移除,list永远是常数时间。
list和vector是两个最常见的容器,如果使用,必须视元素的多寡、构造复杂度、元素存取行为的特性而定。
list节点:
双向链表节点结构
template <class T>
struct _list_node{
typedef void* void_pointer;
void_pointer prev;
void_pointer next;
T data;
}
list迭代器
list不再能像ector一样以普通指针作为迭代器,因为其节点指针无法保证在存储空间中连续存在,list迭代器必须有能力指向list节点,并有能力正确的递增、递减、取值、成员存取等操作,递增:指向下一个节点;递减:指向上一个节点;取值:节点的数据值;成员存取:节点的成员。STL list是一个双向链表,迭代器必须具备前移、后移等能力,所以list提供的迭代器是:定向迭代器(Bidirectional Iterators)。
list还有一个重要特性:插入(insert)操作和接合(splice)操作都不会造成原有的list迭代器失效。
list的数据结构
SGI list不仅是一个双向链表,也是一个环装型双向链表,所以只需要一个指针就能完整表现整个链表:
template <class T,class Alloc = alloc>
class list{
protected:
typedef __list_node<T> list_node;
public:
typedef __list_node* link_type;
protected:
link_type node;///只要一个指针,便可表示整个环状双向链表
}
如果让指针node指向刻意至于尾端的一个空白节点,node便能符合STL对于“前闭后开”区间的要求,成为last迭代器。
list的构造与内存管理
push_back()将新元素插入list尾端,次函数内部调用insert(end(),x);
insert()是一个重载函数,有很多种形式,其中最简单的一种实现方式为:配置并构造一个节点,然后在尾端进行适当的指针操作,将新节点插入进去。
插入操作完成后,新节点将哨兵迭代器所指节点的前方,这是STL对“插入操作”的规范,由于list不像vector那样可能对空间不足做重新配置、数据移动的操作。所以插入之前的所有迭代器在插入操作之后都仍然有效。
list元素重要操作
push_front//头插入
push_back//尾插入
erase//移除迭代器所指的节点
pop_front//移除头节点
pop_back//移除尾节点
clear//清除所有节点
remove//将数值为value的所有元素
unique//移除数值相同的连续元素,只有“连续而相同的元素”,才会被移除剩一个
merge//合并
reverse//元素倒置
sort//排序