相较于vector的连续线性空间,list就显得复杂的多,它的好处是每次插入或删除一个元素,就配置或释放一个元素空间。
因此,list对于空间的运用有绝对的精准,一点不浪费,且对于任何位置的元素插入或者删除,list永远是常数时间。
与之前接触的一样,list本身和list节点结构是分开设计的。
List节点结构如下:
template <class T>
struct __list_node {
typedef void* void_pointer;
void_pointer next;
void_pointer prev;
T data;
};
很清楚的看出是个双向链表,使得整个list的操作变得相对简单些
1、首先看一下list的迭代器设计
template<class T, class Ref, class Ptr>
struct __list_iterator {
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*>const_iterator;
typedef __list_iterator<T, Ref, Ptr> self;
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef __list_node<T>* link_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
//以上,自定义完一些类型名称后:
link_type node; //表明这个迭代器指向的list中的那个节点
//构造函数
__list_iterator(link_type x) : node(x) {}
__list_iterator() {}
__list_iterator(const iterator& x) :node(x.node) {}
bool operator==(const self& x) const { return node == x.node; }
bool operator!=(const self& x) const { return node != x.node; }
//对迭代器取值操作
reference operator*() const { return (*node).data; }
//另一种对成员取值的操作
#ifndef__SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /*__SGI_STL_NO_ARROW_OPERATOR */
//迭代器++,向下移一个节点
self& operator++() {
node = (link_type)((*node).next);
return *this;
}
self operator++(int) {
self tmp = *this;
++*this;
return tmp;
}
self& operator- -() {
node = (link_type)((*node).prev);
return *this;
}
self operator- -(int) {
self tmp = *this;
--*this;
return tmp;
}
};
2、List的数据结构
List的数据结构跟我们想象的差不多,在此基础上,只要在链表尾部后刻意增加一个空白节点,就可以让整个链表形成环形链表。
图中的node(end)节点,即为一个空白节点。
整个链表实现取头、取尾、判断为空都可以依据这个节点来做出判断,如下:
iterator begin() { return(link_type)((*node).next); }
iterator end() { return node; }
bool empty() const { return node->next == node; }
size_type size() const {
size_type result = 0;
distance(begin(), end(), result);
return result;
}
//更方便的是,当我们要交换两个list的内容时,我们只需要:
void swap(list<T, Alloc>& x) { __STD::swap(node,x.node); }
//交换这一个节点就可以了
要注意的是,list的插入操作规范标准是:
插入在…之前
3、list的构造与内存管理
List的内存管理在已有空间配置器的基础上作简单的调用
//配置一个节点的空间
link_type get_node() { returnlist_node_allocator::allocate(); }
//释放/归还一个节点的空间
void put_node(link_type p) {list_node_allocator::deallocate(p); }
//配置并构造一个节点
link_type create_node(const T& x) {
link_type p = get_node();
__STL_TRY {
construct(&p->data, x);
}
__STL_UNWIND(put_node(p));
return p;
}
//析构并释放一个节点
void destroy_node(link_type p) {
destroy(&p->data);
put_node(p);
}
protected:
void empty_initialize() {
node = get_node();
node->next = node;
node->prev = node;
}
//链表的构造函数之一
list() { empty_initialize(); }
4、接着,看一下list中的几个简单算法:
Transfer:(这是几个算法的基础)
//算法目的在于将 [fast, last)内的元素移到 position 元素之前
void transfer(iteratorposition, iterator first, iterator last) {
if (position != last) {
(*(link_type((*last.node).prev))).next =position.node;
(*(link_type((*first.node).prev))).next =last.node;
(*(link_type((*position.node).prev))).next= first.node;
link_type tmp =link_type((*position.node).prev);
(*position.node).prev =(*last.node).prev;
(*last.node).prev = (*first.node).prev;
(*first.node).prev = tmp;
}
}
Splice:(调用Transfer的简单操作)
//将链list中的元素全部移到position中,position所在list和x 必须是不同的
void splice(iterator position, list& x) {
if (!x.empty())
transfer(position, x.begin(), x.end());
}
//将某list中的元素i移到position前面
void splice(iterator position, list&, iterator i) {
iterator j = i;
++j;
if (position == i || position == j)return;
transfer(position, i, j);
}
//将某list中的【first, last)移到 position 前面
void splice(iterator position, list&, iterator first,iterator last) {
if (first != last)
transfer(position, first, last);
}
以下提供merge()和reverse() 、sort()算法
Merge():
//这个算法不多说,就跟普通的归并一样
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 (*first2 < *first1) {
iterator next = first2;
transfer(first1, first2, ++next);
first2 = next;
}
else
++first1;
if (first2 != last2) transfer(last1, first2, last2);
}
Reverse:
template <class T,class Alloc>
void list<T,Alloc>::reverse() {
//先判断是不是0个或1个节点
if (node->next == node ||link_type(node->next)->next == node)return;
//主要思想是利用begin()和transfer()来实现
//比如先指向第二个元素,利用transfer移到begin()前面,原先指向第二个元素的迭代器指向第三个,重复直到最后
iterator first = begin();
++first;
while (first != end()) {
iterator old = first;
++first;
transfer(begin(), old, first);
}
}
Sort有点看不懂,先放着