list概述
相较于vector的连续空间,list就显得复杂的多,它的好处是每次插入或删除一个元素,就配置或释放一个元素空间。
list的节点(node)
STL list的节点(node)结构:
template < class T>
struct __list_node{
typedef void* void_pointer;
void_pointer prev;//型别为void*,其实可设为__list_node< T >*
void_pointer next;
T data
};
list的迭代器
list迭代器必须有能力指向list的节点,并有能力进行正确的递增、递减、取值、成员存取等操作。由于STL list是一个双向链表,迭代器必须具备前移、后移的能力,所以list提供的是Bidrectional iterators.
list的一个重要性质:插入操作(insert)和接合操作(splice)都不会造成原有的list迭代器失效。甚至list的元素的删除操作(erase),也只有“指向被删除元素”的那个迭代器失效,其他迭代器不受任何影响。
list的数据结构
SGI list不仅是一个双向链表,而且还是一个环状双向链表,所以它只需要一个指针,便可以完整表现整个链表。
是环状链表秩序一个标记,即可完全表示整个链表,只要刻意在环状链表的尾端加上一个空白节点,便符合STL规范址“前闭后开”区间。
list的构造与内存管理:constructor,push_back,insert
当我们以push_back()将新元素插入于list尾端时,此函数内部调用insert();
void push_back(const T& x){insert(end(), x);}
insert()是一个重载函数,有多种形式,其中最简单的一种如下,首先配置并构造一个节点,然后在尾端进行适当的指针操作,将新阶段插入进去。
//函数目的:在迭代器position所指位置插入一个节点,内容为x
iterator insert(iterator position const T&x){
link_type tmp = create_node(x);//产生一个节点(设置内容为x)
//调整双向指针,使tmp插入进去
tmp->next = position.node;
tmp->prev = position.node->prev;
(link_type(position.node->prev))->next = tmp;
position.node->prev = tmp;
return tmp;
}
注意,插入完成后,新阶段将位于哨兵迭代器(标示出插入点)所指之节点的前方——这是STL对于“插入操作”的标准规范。
所谓插入指的是“插在…之前”
list的元素操作:push_front, push_back, erase, pop_front, pop_back, clear, remove, unique, splice, merge, reverse, sort
//插入一个节点作为头节点
void push_front(consst T& x){insert(begin(), x);}
//插入一个节点,作为尾节点
void push_back(const T& x){ insert(end(), x);}
//移除迭代器position所指节点
iterator erase(iterator position){
link_type next_node = link_type(position.node->next);
link_type prev_node = link_type(position.node->prev);
prev_node->next = next_node;
next_node->prev = prev_node;
destroy_node(position.node);
return iterator(next_node);
}
//移除头结点
void pop_front(){erase(begin);}
//移除尾结点
void pop_back(){
iterator tmp = end();
erase(–tmp);
}
//清除所有节点(整个链表)
template < class T, class Alloc>
void list< T, Alloc>::clear(){//遍历每个节点
link_type cur = (link_type) node->next;
while(cur != node){
link_type tmp = cur;
cur = (link_type) cur->next;
destroy_node(tmp);//销毁(析构并释放)一个节点
}
//恢复node原始状态
node->next = node;
node->prev = node;
}
list内部提供一个所谓的迁移操作(transfer):将某连续范围的元素迁移到特定位置之前,这个操作为其他的复杂操作如splice, sort, merge等奠定良好的基础。
迁移操作就是将(first, last)内的所有元素移到position之前,过程如下图:
list公开提供的是所谓的接合操作(splice):将某连续范围的元素从一个list移动到另一个(或同一个)list的某个定点。
//将x结合于position所指位置之前,x必须不同于*this
void splice(iterator position, list& x){
if(!x.empty()){
transfer(position, x.begin(), x.end());
}
}
//merge()将x合并到*this身上,两个lists的内容都必须先经过递增排序
template< class T, class Alloc>
void list< T, Alloc>::merge(list < T, Alloc>& x){
iterator first1 = begin();
iterator last1 = end();
iterator first2 = x.begin();
iterator last2 = x.end();
while(first1 != last1 && first2 != last2){
if(*first1 < *first2){
iterator next = first2;
transfer(first, first2, ++next);
first2 = next;
}
else
++first;
if(first2 != last2) transfer(last1, first2, last2);
}
}