list不能像vector那样以普通指针作为迭代器,因为其节点不保证在储存空间中连续存在。因为要保证迭代器能进行operator++, operator--,所以STL list是一个双向链表。
list比vector好的地方在于,插入操作(insert)和接合操作(splice)都不会使原有的迭代器失效。(上一篇介绍过,vector会在扩充空间时使得原有迭代器失效)。但是删除操作(erase)还是会使”指向被删除元素“的那个迭代器失效。
list的节点结构如下:
list的数据结构如下:template <class T> struct __list_node { typedef void* void_pointer; void_pointer prev; //型别为void*,其实可设为__list_node<T>* void_pointer next; T data; }
值得一提的是,list不仅是一个双向链表,而且还是一个环状双向链表,所以它只需要一个指针,就可以完整表现整个链表。而且会使node指向刻意置于尾端的一个空白节点,这样就能符合STL对于”前闭后开“的区间要求。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; // 只要一个指针,便可表示完整的环状双向链表 }
如此一来,list的几个成员函数便可以很简单的实现:
iterator begin() { return (link_type)((*node).next); } iterator end() { return node; } bool empty() const { return node->next == node; }
list的push_back(), push_front()都是调用的insert(),pop_front(), pop_back()都是调用erase(), 这些操作都双向链表来说都是相当简单的。
值得注意的是,list内部提供一个非公开的接口transfer(iterator pos, iterator i, iterator j),把[i, j)内的所有元素移到pos之前。这个函数在list内部发挥了重要的作用。
splice()函数把某连续范围的元素从一个List移到另一个(或同一个)list的某个定点,它内部只是简单调用transfer()而已。
merge(list& x)把另一个list合并到*this中,但前提是两个list都必须先经过递增排序,并在合并后保持递增顺序。如果不关心排序,就用splice()好了。
reverse()从第二个结点开始,循环调用transfer(),每次把一个结点移动到头结点前面,以实现反向。
sort()使用快速排序法,并在内部使用到splice()。注意list不能使用STL的算法sort(),必须使用自己的成员函数sort(),因为STL算法sort()只接受RamdonAccessIterator.