1. 程式人生 > >STL原始碼分析之slist有序容器 上

STL原始碼分析之slist有序容器 上

前言

不同於listForward Iterator型別的雙向連結串列, slist是單向連結串列, 也是Bidirectional Iterator型別. slist主要耗費的空間小, 操作一些特定的操作更加的快, 同樣類似與slist, 在執行插入和刪除操作迭代器都不會像vector使迭代器失效. slist主要的問題在於它是單向的, 正向迭代器, 只有push_front, 沒有push_back的操作, 指定位置之後的插入和刪除時間都是O(1), 而在指定位置之前插入就需要重新遍歷連結串列時間就是O(n), 效率很低.

slist原始碼

slist的構成與list

還是異曲同工.

節點結構

將節點的每一部分都進行剝離, 節點是一個結構構成, 資料是繼承節點.

struct __slist_node_base
{
  __slist_node_base* next;	// 只有指向下一個節點的指標
};
// 繼承節點指標, __slist_node增加資料
template <class T>
struct __slist_node : public __slist_node_base
{
  T data;
};

節點的操作

在節點指定節點後插入新的節點.

inline __slist_node_base* __slist_make_link
(__slist_node_base* prev_node, __slist_node_base* new_node) { new_node->next = prev_node->next; prev_node->next = new_node; return new_node; }

尋找指定節點的prev節點. 因為slist是正向迭代器就只有遍歷連結串列

inline __slist_node_base* __slist_previous(__slist_node_base* head, const __slist_node_base* node)
{
// 遍歷整個連結串列來尋找 while (head && head->next != node) head = head->next; return head; } inline const __slist_node_base* __slist_previous(const __slist_node_base* head,const __slist_node_base* node) { // 遍歷整個連結串列來尋找 while (head && head->next != node) head = head->next; return head; }

將指定範圍的連結串列剪下到pos連結串列後

inline void __slist_splice_after(__slist_node_base* pos,__slist_node_base* before_first, __slist_node_base* before_last)
{
  if (pos != before_first && pos != before_last) {
    __slist_node_base* first = before_first->next;
    __slist_node_base* after = pos->next;
      // 將before_first之後的調整為before_last後面的連結串列
    before_first->next = before_last->next;
      // 將[before_first->next, before_last]插入到pos之後
    pos->next = first;
    before_last->next = after;
  }
}

將連結串列進行倒轉

inline __slist_node_base* __slist_reverse(__slist_node_base* node)
{
  __slist_node_base* result = node;
  node = node->next;
  result->next = 0;
  while(node) {
      // 將原連結串列一一的插入到臨時連結串列的尾, 實現連結串列的元素倒轉
    __slist_node_base* next = node->next;
    node->next = result;
    result = node;
    node = next;
  }
  return result;
}

迭代器

之前說過slist的迭代器是正向的, 現在就來具體分析.

__slist_iterator_base單向連結串列的迭代器基本結構

struct __slist_iterator_base
{
    // 定義型別
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  typedef forward_iterator_tag iterator_category;
	// 定義節點指標
  __slist_node_base* node;
	// 建構函式
  __slist_iterator_base(__slist_node_base* x) : node(x) {}
    // incr: 只正向.
  void incr() { node = node->next; }
	// 只過載了==,!=
  bool operator==(const __slist_iterator_base& x) const {
    return node == x.node;
  }
  bool operator!=(const __slist_iterator_base& x) const {
    return node != x.node;
  }
};

__slist_iterator單向連結串列迭代器結構. 只過載實現了++操作, 沒有–, 因為就只是正向迭代, --操作就需要重新遍歷連結串列.

template <class T, class Ref, class Ptr>
struct __slist_iterator : public __slist_iterator_base
{
	// 定義迭代器
  typedef __slist_iterator<T, T&, T*>             iterator;
  typedef __slist_iterator<T, const T&, const T*> const_iterator;
  typedef __slist_iterator<T, Ref, Ptr>           self;
	// 滿足traits程式設計
  typedef T value_type;
  typedef Ptr pointer;
  typedef Ref reference;
  	// 定義連結串列節點
  typedef __slist_node<T> list_node;
	// 建構函式
  __slist_iterator(list_node* x) : __slist_iterator_base(x) {}
  __slist_iterator() : __slist_iterator_base(0) {}
  __slist_iterator(const iterator& x) : __slist_iterator_base(x.node) {}
	// 獲得當前指標的值
  reference operator*() const { return ((list_node*) node)->data; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

	// 對++過載
  self& operator++()
  {
    incr(); // 指向下一個節點
    return *this;
  }
  self operator++(int)
  {
    self tmp = *this;
    incr();
    return tmp;
  }
};

#ifndef __STL_CLASS_PARTIAL_SPECIALIZATION
inline ptrdiff_t* distance_type(const __slist_iterator_base&)
{
  return 0;
}
inline forward_iterator_tag iterator_category(const __slist_iterator_base&)
{
  return forward_iterator_tag();
}
template <class T, class Ref, class Ptr> 
inline T*  value_type(const __slist_iterator<T, Ref, Ptr>&) {
  return 0;
}
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

通過遍歷整個連結串列計算連結串列的長度.

inline size_t __slist_size(__slist_node_base* node)
{
  size_t result = 0;
  for ( ; node != 0; node = node->next)
    ++result;
  return result;
}

slist分析

slist型別定義.

template <class T, class Alloc = alloc>
class slist
{
public:
    // 滿足traits程式設計
  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;	// 定義空間配置器

private:
  list_node_base head;	// 定義節點的頭
    ...	
};
slist建構函式
template <class T, class Alloc = alloc>
class slist
{
	...
public:
  slist() { head.next = 0; }	// 預設建構函式, head.next == 0

    // 以下建構函式都呼叫fill_initialize填充連結串列
  slist(size_type n, const value_type& x) { fill_initialize(n, x); }
  slist(int n, const value_type& x) { fill_initialize(n, x); }
  slist(long n, const value_type& x) { fill_initialize(n, x); }
  explicit slist(size_type n) { fill_initialize(n, value_type()); }	// 不能隱式呼叫該建構函式

#ifdef __STL_MEMBER_TEMPLATES
    // 接受兩個迭代器, 範圍初始化
  template <class InputIterator>
  slist(InputIterator first, InputIterator last) {
    range_initialize(first, last);
  }
#else /* __STL_MEMBER_TEMPLATES */
  slist(const_iterator first, const_iterator last) {
    range_initialize(first, last);
  }
  slist(const value_type* first, const value_type* last) {
    range_initialize(first, last);
  }
#endif /* __STL_MEMBER_TEMPLATES */
	...
};

fill_initialize, 初始化

void fill_initialize(size_type n, const value_type& x) {
    head.next = 0;
    __STL_TRY {
      _insert_after_fill(&head, n, x);
    }
    __STL_UNWIND(clear());
}

range_initialize, 自定義範圍初始化

template <class T, class Alloc = alloc>
class slist
{
	...
private:
#ifdef __STL_MEMBER_TEMPLATES
  template <class InputIterator>
  void range_initialize(InputIterator first, InputIterator last) {
    head.next = 0;
    __STL_TRY {
      _insert_after_range(&head, first, last);
    }
    __STL_UNWIND(clear());
  }
#else /* __STL_MEMBER_TEMPLATES */
  void range_initialize(const value_type* first, const value_type* last) {
    head.next = 0;
    __STL_TRY {
      _insert_after_range(&head, first, last);
    }
    __STL_UNWIND(clear());
  }
  void range_initialize(const_iterator first, const_iterator last) {
    head.next = 0;
    __STL_TRY {
      _insert_after_range(&head, first, last);
    }
    __STL_UNWIND(clear());
  }
#endif /* __STL_MEMBER_TEMPLATES */
	...
};

range_initialize和fill_initialize函式都是呼叫_insert_after_range, _insert_after_range也是有多個過載函式.

_insert_after_range, 初始化成員屬性

template <class T, class Alloc = alloc>
class slist
{
	...
private:
  void _insert_after_fill(list_node_base* pos,
                          size_type n, const value_type& x) {
      // 構造出n個節點並初始化為x
    for (size_type i = 0; i < n; ++i)
      pos = __slist_make_link(pos, create_node(x));
  }

#ifdef __STL_MEMBER_TEMPLATES
  template <class InIter>
  void _insert_after_range(list_node_base* pos, InIter first, InIter last) {
      // 構造出 [first, last) 個節點並初始化為first
    while (first != last) {
      pos = __slist_make_link(pos, create_node(*first));
      ++first;
    }
  }
#else /* __STL_MEMBER_TEMPLATES */
  void _insert_after_range(list_node_base* pos,
                           const_iterator first, const_iterator last) {
      // 構造出 [first, last) 個節點並初始化為first
    while (first != last) {
      pos = __slist_make_link(pos, create_node(*first));
      ++first;
    }
  }
  void _insert_after_range(list_node_base* pos,
                           const value_type* first, const value_type* last) {
      // 構造出 [first, last) 個節點並初始化為first
    while (first != last) {
      pos = __slist_make_link(pos, create_node(*first));
      ++first;
    }
  }
#endif /* __STL_MEMBER_TEMPLATES */
    ...
};

create_node函式, 呼叫空間配置器分配空間然後在呼叫建構函式

template <class T, class Alloc = alloc>
class slist
{
	...
private:
  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;
  }
	...
};
解構函式
template <class T, class Alloc = alloc>
class slist
{
	...
private:
    ~slist() { clear(); }	// 呼叫clear函式將所有元素進行刪除和釋放
    ...
};

destroy_node函式, 呼叫解構函式之後再釋放空間

template <class T, class Alloc = alloc>
class slist
{
	...
private:
  static void destroy_node(list_node* node) {
    destroy(&node->data);	// 呼叫解構函式
    list_node_allocator::deallocate(node);	// 釋放記憶體空間
  }
	...
};
拷貝建構函式
template <class T, class Alloc = alloc>
class slist
{
	...
private:
    // 直接呼叫range_initialize函式進行初始化
  slist(const slist& L) { range_initialize(L.begin(), L.end()); }
    ...
};

總結

本節只是對slist的基本構成, 建構函式和解構函式做了一個探討, 下一節就準備分析slist的刪除, 插入等具體操作的實現.