【STL源码剖析读书笔记】【第4章】序列式容器之list和slist

一、list

1、list概述

list是双向链表,对于任何位置的元素插入或元素移除,list永远是常数时间。

2、list的节点

list本身和list节点是不同的数据结构,需要分开设计。STL list的节点结构:

template <class T>
struct __list_node {
  typedef void* void_pointer;
  void_pointer next;
  void_pointer prev;
  T data;
};
3、 list 的迭代器

STL list是一个双向链表,迭代器必须具备前移、后移的能力,list提供的是Bidirectional Iteratorslist的插入操作和接合操作都不会导致原来的list迭代器失效。


4、list的数据结构

STL list是一个环状双向链表,只需一个指针就可以表现整个链表。

template<class T,class Alloc = alloc> //缺省使用alloc为配置器:w
class list{
protected :
	typedef	__list_node<T> list_node ;
public  :
	typedef	list_node* link_type ;
protected :
	link_type node ; //只要一个指针,便可以表示整个环状双向链表
};
如果让指针 node 指向刻意置于尾端的一个空白节点, node 便能符合 STL 对于“前闭后开”区间的要求,成为 last 迭代器。


5、insert()函数

insert()是一个重载函数,最简单的一种如下:

iterator insert(iterator position, const T& x){//在迭代器position所指位置插入一个节点,内容为x
	link_type tmp = create_node(x);
	tmp->next = position.node;
	tmp->prev = position.node->node;
	(link_type(position.node->prev))->next = tmp;
	return tmp;
}

6、push_back()函数

将新元素插入于list尾端,内部调用insert()函数

void push_back(const T& x){
insert(end(),x);
}
7、 push_front() 函数

将新元素插入于list头端,内部调用insert()函数

void push_front(const T&x){
insert(begin(),x);
}
8、 erase() 函数

iterator erase(iterator position){
link_type next_node=link_type(position.node->next);
link_type prev_node=link_type(position.node->prev_nodext);
prev_node->next=next_node;
next_node->prev=prev_node;
destroy_node(position.node);
return iterator(next_node);
}

9、pop_front()函数

移除头结点,内部调用erase()函数

void pop_front(){
erase(begin());
}
10、 pop_back() 函数

移除尾结点,内部调用erase()函数

void pop_back(){
iterator i=end();
erase(--i);
}
11、 transfer() 函数

将某连续范围的元素迁移到某个特定位置之前。

void transfer(iterator position, iterator first, iterator last) {
    if (position != last) {
      (*(link_type((*last.node).prev))).next = position.node; //(1)
      (*(link_type((*first.node).prev))).next = last.node;    //(2)
      (*(link_type((*position.node).prev))).next = first.node;//(3)
      link_type tmp = link_type((*position.node).prev);       //(4)
      (*position.node).prev = (*last.node).prev;              //(5)
      (*last.node).prev = (*first.node).prev;                 //(6)
      (*first.node).prev = tmp;                               //(7)
    }
  }

二、slist

1slist概述

SGI STL另提供一个单向链表slistslistlist的主要差别在于,前者的迭代器属于单向的Forward Iterator,后者的迭代器属于双向的BidirectionalIterator

根据STL的习惯,插入操作会将新元素插入于指定位置之前。作为单向链表,slist没有任何方便的方法可以回头定出前一个位置,因此它必须从头找起。

2、slist的节点

3、slist的迭代器


4、slist的数据结构

template<class T, class Alloc = alloc>
class slist
{
public :
	typedef	T	value_type ;
	typedef	value_type*	pointer ; 
	typedef	const	value_type*	const_pointer ;
	typedef	value_type&	reference ;
	typedef	const value_type& const_reference ;
	typedef	size_t	size_type ;
	typedef	ptrdiff_t	difference_type ;


	typedef	__slist_iterator<T,T&,T*>	iterator ;
	typedef	__slist_iterator<T,const T&,const T*> const_iterator ;

private :
	typedef	__slist_node<T>	list_node ;
	typedef	__slist_node_base	list_node_base ;
	typedef	__slist_iterator_base	iterator_base ;
	typedef simple_alloc<list_node,Alloc> list_node_allocator ;

	static	list_node* create_node(const value_type& x)
	{
		list_node* node = list_node_allocator:;allocate() ; //配置空间
		__STL_TRY{
			construct(&node->data,x) ;
			node->next = 0 ;
		}
		__STL_UNWIND(list_node_allocator:;deallocate(node)) ;
		return node ;
	}

	static void destroy_node(list_node* node)
	{
		destroy(&node->data) ; //将元素析构	
		list_node_allocator::deallocate(node) ; //释放空间
	}

private :
	list_node_base head  ; //头部。注意,它不是指针,是实物
			

public:
	slist() {head.next = 0 ;} 
	~slist(){clear() ;}

public :
	iterator begin() {return iterator((list_node*)head.next) ;}
	iterator end() {return iteator(0) ;}
	iterator size() {const __slist_size(head.next) ;}
	bool empty() const {return head.next == 0 ;} 

	//两个slist互换:只要将head交换互指即可
	void swap(slist &L)
	{
		list_node_base* tmp = head.next;
		head.next = L.head.next ;
		L.head.next = tmp ;
	}

public :
	//取头部元素
	reference front() {return ((list_node*)head.next)->data ;}

	//从头部插入元素(新元素成为slist的第一个元素)
	void push_front(const value_type& x)
	{
		__slist_make_link(&head,create_node(x)) ;
	}

	//注意,没有push_back()
	
	//从头部取走元素(删除之)。修改head
	void pop_front()
	{
		list_node* node = (list_node*)head.next ;
		head.next = node->next ;
		destroy_node(node);
	}
	.....
}  ;
5、 slist 的元素操作





你可能感兴趣的:(【STL源码剖析读书笔记】【第4章】序列式容器之list和slist)