List节点结构:
template <class T>
struct __list_node {
typedef void * void_pointer;
void_pointer prev;
void_pointer next;
T data;
};
prev指向前一个节点,next指向下一个节点。
List的迭代器类,属于bidirectional iterator,定义了三个构造函数,其中__list_iterator (link_type x) : node(x){ } 是将list node指针赋值给node成员;另外还重载了运算符* , -> , ++ , -- , == , !=;迭代器中其他都是围绕着link_type node这个中心成员,而这个成员是指向__list_node<T>的指针;
template <class T , class Ref, class Ptr>
struct __list_iterator {
typedef __list_iterator<T , T& , T*> iterator;
typedef __list_iterator<T , Ref, Ptr> self;
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref referece;
typedef __list_node<T>* link_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
link_type node;
__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}
referece operator*() const { return (*node).data } //node的值
pointer operator->() const { return &(operator*())} //node的成员data的地址
self & operator++(){ //++x
node = (link_type) ((*node).next);
return *this;
}
self operator++(int){ //x++
self tmp = *this;
++ *this;
return tmp;
}
self& operator--(){
node = (link_type)((*node).prev);
return *this;
}
self operator--(int){
self tmp = *this;
-- *this;
return tmp;
}
};
下面引入list容器类,简化的定义,这里我只写出自己感兴趣的一些成员变量和成员函数;
list容器是个循环指针链表,其中node节点起的作用是非常大的,主要用来表示该链表的是否为空,链表的first和last,使用构造函数list()产生的是一个空的list,一个空的list为:
在list容器的定义式中可以看到,iterator/const_iterator是list中的嵌套类型(nested type),
template <class T , class Alloc = alloc>
class list {
protected:
typedef __list_node<T> list_node;
public:
typedef list_node* link_type;
typedef simple_alloc<list_node , Alloc> list_node_allocator;
typedef __list_iterator<T, T& , T*> iterator;
typedef __list_iterator<T, const T& , const T*> const_iterator;
protected:
link_type node;
public:
list() { empty_initialize();}
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;
}
referece front() {return *begin();}
referece back(){ return *(--end());}
void push_back (const T& x) { insert(end() , x); }
void push_front (const T& x) { insert(begin() , x); }
void pop_front () { erase(begin()); }
void pop_back() { erase(--end()); }
void clear();
void remove(const T& value);
void unique();
void sort();
void splice(iterator position , list& x) {
if ( !x.empty() ) {
transfer(position , x.begin() , x.end());
}
}
void splice(iterator position , list& , iterator i) {
iterator j = i;
++j;
if (position == i || position == j) return;
transfer(position , i , j);
}
void splice(iterator position , iterator first ,iterator last) {
if (first != last)
transfer(position , first , last);
}
void merge(list<T,Alloc>& x) {
iterator first1 = begin();
iterator last1 = end();
iterator firs2 = x.begin();
iterator last2 = x.end();
while (first1 != last1 && first2 != last2)
if (*first1 > *first2) {
iterator next = first2;
transfer(first1,first2,++next);
first2 = next;
}
else
first1++;
if (first2 != last2)
transfer(last1,first2,last2);
}
void reverse() {
if (node->next == node || link_type(node->next)->next == node) return;
iterator first = begin();
++first;
while(fist != end()) {
iterator old = first;
++first;
transfer(begin() , old , first);
}
}
iterator insert(iterator position , const T& x) {
link_type tmp = create_node (x);
tmp->next = position.node;
tmp->prev = position.node->prev;
link_type(position.node->prev)->next = tmp;
position.node->prev = tmp;
return tmp;
}
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);
}
protected:
link_type get_node() {
return list_node_allocator::allocator();
}
void put_node( link_type p) {
list_node_allocator::deallocate(p);
}
link_type create_node (const T& x) {
link_type p = get_node();
construct (&p->data , x);
return p;
}
void destroy_node (link_type p) {
destroy (& p->data);
put_node(p);
}
void empty_initialize() {
node = get_node();
node->next = node;
node->prev = node;
}
void transfer(iterator position , 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;
}
}
};
上面的几个成员函数spice , merge ,reverse以及没有列出来的成员函数很多都使用了函数transfer,这个函数的过程我也来用图备注下
将区间 [first , last)间的节点挪到position节点前面,显然如果position等于last的话,就是讲[first,last)间的节点移动到last之后,等于没有移动,所以在移动之前加了个判断下面就一行一行的表示了指针改动过程.
最后,形成了这样的链表:
最后我说下,其中如果是迭代器iterator的话,我们要用的是iterator成员node,而不是iterator本身,node是list的节点。
补充下,关于SGI STL List 中的sort函数,因为List是bidirectional iterator,而STL算法sort()只接受ramdon access iterator;
template <class T , class Alloc>
void list<T , Alloc>::
sort()
{
if(node->next == node || link_type(node->next)->next == node)
return;
list<T,Alloc> carry;
list<T,Alloc> counter[64];
int fill = 0;
while( !empty() ) {
splice(carry , *this , begin());
int i = 0;
while(i < fill && !counter[i].empty()) {
counter[i].merge(carry);
carry.swap(counter[i++]);
}
carry.swap(counter[i]);
if ( i == fill) ++fill;
}
for (int i = 1 ; i < fill ; ++i)
counter[i].merge(counter[i - 1]);
swap(counter[fill - 1]);
}
这里的sort使用的快速排序,现在我来用图和问题来推到下这个快速排序的过程。
1)
splice(carry , *this , begin());
carry将第一个节点2摘下来:
然后while循环条件不成立,执行carry.swap( counter[ 0 ] ) , 执行完后 , carry为空,counter [0]为节点2;
i == fill == 0 所以fill++ , 则有fill == 1;
2)
splice(carry , *this , begin());
carry将第2个节点8摘下来:
然后执行while循环,因为此时fill == 1,所以只执行一次循环;
counter[0].merge(carry);
carry.swap(counter[0]);
carry.swap(counter[1]);
执行之后,counter[0]为NULL,counter[1]为节点2和8的链表;
fill = 2;
3)
splice(carry , *this , begin());
carry将第3个节点1摘下来:
此时counter[0]为empty,不执行whiie循环体;
carry.swap(counter[0]);
i == 0 ,fill == 2; 然后继续下一步;
4):
splice(carry , *this , begin());
carry将第4个节点1摘下来:
进入while循环;
i == 0:
counter[0].merge(carry);
carry.swap(counter[0]);
counter为空;
i == 1:
counter[1].merge(carry);
carry.swap(counter[1]);
此时counter[0]和counter[1]都是空;
跳出循环后执行carry.swap(counter[i]);
所以counter[2]为:
fill ++ 得 fill == 3;
5)
splice(carry , *this , begin());
carry将第5个节点3摘下来,因为此时counter[0]为空,所以不进入循环,执行carry.swap( counter[0] );
6)
splice(carry , *this , begin());carry将第6个节点5摘下来:
counter[0].merge(carry);
carry.swap(counter[0]);
carry.swap(counter[1]);
7)
splice(carry , *this , begin()); carry将第7个节点6摘下来,然后和counter[0] swap:
8)
splice(carry , *this , begin()); carry将第8个节点4也就是最后一个节点摘下来;
此时fill == 3,counter[0...2]都不是empty,所以while循环会执行三次:
i == 0:
counter[0].merge(carry);
carry.swap(counter[0]);
i == 1
counter[1].merge(carry);
carry.swap(counter[1]);
i == 2
counter[2].merge(carry);
carry.swap(counter[2]);
跳出循环,执行
carry.swap(counter[3]);
然后fill == 3;
this->empty()为真,跳出while循环;
此时counter[0..2]为空,counter[3]中为排序完成后的链表;
所以最后执行:
for (int i = 1 ; i < fill ; ++i)
counter[i].merge(counter[i - 1]);
swap(counter[fill - 1]);
将counter[3]和this交换,得到排序后的数据。
OK,例子分析完成,最后我再说明下显而易见的原理,其中counter[i]存放2^i个链表节点,一旦存满之后就和counter[i+1]进行merge,而merge操作是将两个排序号好的链表并在一起,被并者最后为空,counter[ i + 1]为排序好的链表,然后将counter[i + 1]和counter[i + 2]交换....... 其中counter为长度为64的数组,所以最多可以处理排序2^64 - 2节点的链表。
最后,这次真的饿是最后,对比下ramdon access iterator使用的sort算法:
template <typename T>
void quick_sort(T A[] ,int p , int r)
{
if (p < r) {
int q = partition (A , p , r);
quick_sort(A , p , q - 1);
quick_sort(A , q + 1 , r);
}
}
template <typename T>
int partition(T A[] , int p , int r)
{
T x = A[r - 1];
int i = p - 1;
for (int j = p ; j < r - 1; ++ j) {
if ( A[j] <= x) {
++i;
swap(A[i] , A[j]);
}
}
swap(A[i + 1] , A[r - 1]);
return i + 1;
}