STL源码剖析之list

来源:互联网 发布:java webstart 编辑:程序博客网 时间:2024/05/17 06:47

相较于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有点看不懂,先放着

0 0