STL原始碼分析之slist有序容器 上
前言
不同於list
是Forward 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
的刪除, 插入等具體操作的實現.