STL 容器List

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摘下来:


此时fill == 3,counter[0]有一个节点,counter[1]为空,所以while一次,跳出循环后执行carry和counter[1]的交换;

        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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值