STL之list源码剖析
2014-04-01 17:01
477 查看
STL之list源码剖析
相较于vector,使用list的好处是每次插入或删除一个元素,就配置或释放一个元素的空间。list的节点:
template<class T>
struct __list_node{
typedefvoid* void_pointer;
void_pointerprev; //型别为void*。其实可设为__list_node<T>*
void_pointernext;
Tdata;
};
显然这是一个双向链表。
list迭代器
list不再能够像vector一样以普通指针作为迭代器,因为其节点不保证在存储空间中连续。List迭代器必须有能力指向list的节点,并有能力进行正确的递增、递减、取值、成员存取等操作。
由于STL list是一个双向链表,迭代器必须具备前移、后移的能力,所以list提供的是bidirectional Iterators。
list有一个重要性质:插入操作和结合操作都不会造成原有的list迭代器失效,甚至删除操作也只有”指向被删除元素”的那个迭代器失效,其他迭代器不受影响。
以下是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;
typedefbidirectional_iterator_tag iterator_category;
typedefT value_type;
typedefPtr pointer;
typedefRef reference;
typedef__list_node<T>* link_type;
typedefsize_t size_type;
typedefptrdiff_t difference_type;
link_type node;
__list_iterator(link_type x) : node(x) {}
__list_iterator() {}
__list_iterator(const iterator& x) : node(x.node) {}
booloperator==(const self& x) const { return node == x.node; }
bool operator!=(constself& x) const { return node != x.node; }
reference operator*() const { return (*node).data; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointeroperator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
self& operator++() {
node= (link_type)((*node).next);
return *this;
}
selfoperator++(int) {
selftmp = *this;
++*this;
return tmp;
}
self& operator--() {
node= (link_type)((*node).prev);
return *this;
}
selfoperator--(int) {
selftmp = *this;
--*this;
return tmp;
}
};
list的数据结构
list不仅是一个双向链表,而且还是一个环状双向链表。所以他只需要一个指针,便可以完整表现整个链表:
template<class T,class Alloc= alloc>
//缺省使用alloc为配置器
classlist{
protected:
typedef __list_node<T> list_node;
public:
typedef list_node* link_type;
protected:
link_typenode; //只要一个指针,便可表示整个环状双向链表
...
};
让指针node指向置于尾端的一个空白节点,node变能符合STL对于”前开后闭”区间的要求,成为last(或者说end())迭代器。
如下图所示:
于是,以下几个函数便可以轻松完成:
iterator begin(){ return (link_type)((*node).next); }
iterator end(){ returnnode; }
boolempty()
const { returnnode->next == node; }
size_type size() const{
size_typereslut = 0;
distance(begin(),end(), result);
return result;
}
//取头结点的内容(元素值)
reference front(){ return *begin(); }
//取尾节点的内容(元素值)
reference back(){ return *(--end()); }
list的构造与内存管理:
list缺省使用alloc作为空间配置器,并据此另外定义了一个list_node_allocator,为方便以节点大小为配置单位:
template <class T, class Alloc = alloc>
class list{
protected:
typedef__list_node<T> list_node;
typedefsimple_alloc<list_node, Alloc>list_node_allocator;
…
};
以下四个函数用来配置、释放、构造、销毁一个节点:
protected:
link_type get_node() { return list_node_allocator::allocate(); }
voidput_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;
}
voiddestroy_node(link_type p) {
destroy(&p->data);
put_node(p);
}
list提供许多constrors,其中一个是defaultconstructors,允许我们不指定任何参数做出一个空的list出来:
public:
list(){ empty_initialize(); }
protected:
voidempty_initialize() {
node= get_node(); //配置一个节点空间,令node指向它
node->next = node; //令node头尾都指向自己,不设元素值
node->prev = node;
}
push_back()函数的实现:
void push_back(const T& x) { insert(end(),x); }
insert是一个重载函数,有多重形式,以下是最简单的一种:
//函数目的:在迭代器position所指位置插入一个节点,内容为x
iterator insert(iterator position, const T&x) {
link_type tmp =create_node(x); //产生一个节点(设内容为x)
//调整双向指针,使tmp插入进去
tmp->next =position.node;
tmp->prev = position.node->prev;
(link_type(position.node->prev))->next = tmp;
position.node->prev = tmp;
return tmp;
}
注意,插入节点完成后,新节点位于哨兵迭代器所指节点的前方。
list的元素操作
list的主要元素操作有push_front, push_back, erase, pop_front, pop_back, clear,remove, unique,splice,merge,reverse,sort。
这里主要分析下splice,merge,reverse,sort这四个操作。
list内部提供一个所谓的迁移操作(transfer):将某连续范围内的元素迁移到某个特定位置之前。下面是transfer的源代码:
protected:
voidtransfer(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;
}
}
下图展现transfer的实现:
上述的transfer并非公开接口。list公开提供的是所谓的接合操作(splice):将某个连续范围的元素从一个list移动到另一个(或同一个)list的某个定点。下面是splice几个版本的实现:
public:
voidsplice(iterator position, list& x) {
if(!x.empty())
transfer(position, x.begin(), x.end());
}
voidsplice(iterator position, list&, iterator i) {
iterator j = i;
++j;
if(position == i || position == j) return;
transfer(position, i, j);
}
voidsplice(iterator position, list&, iterator first, iterator last) {
if(first != last)
transfer(position, first, last);
}
以下是merge(),reverse(), sort()的源代码:
//merge()将x合并到*this身上。两个lists的内容都必须先经过排序 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()将*this的内容你想重置 template <class T, class Alloc> void list<T, Alloc>::reverse() { //以下判断,如果是空链表,或仅有一个元素,就不进行任何操作 if(node->next == node || link_type(node->next)->next == node) return; iterator first = begin(); ++first; while(first != end()) { iterator old = first; ++first; transfer(begin(), old, first); } } //list不能使用STL算法sort(),必须使用自己的sort() memberfunction //因为STL算法sort()只接受RamdonAccessIterator //本函数采用quick sort template <class T, class Alloc> void list<T, Alloc>::sort() { //以下判断,如果是空链表,或仅有一个元素,就不进行任何操作 if(node->next == node || link_type(node->next)->next == node) return; //一些新的lists,作为中介数据存放区 list<T, Alloc> carry; list<T, Alloc> counter[64]; intfill = 0; while(!empty()) { carry.splice(carry.begin(), *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]); }
相关文章推荐
- 【STL】list源码剖析
- STL 之 list 源码剖析
- STL源码剖析学习五:list
- STL之list源码剖析
- STL学习笔记之容器--list(二)源码剖析
- STL 源码剖析读书笔记三:序列式容器之 vector、list
- STL源码剖析学习二:空间配置器(allocator)
- STL 源码剖析之四:序列式容器
- STL源码分析--list
- LinkedList源码剖析
- STL源码分析----神奇的 list 的 sort 算法实现
- STL 源码剖析 算法 stl_heap.h
- LinkedList源码剖析
- STL之deque源码剖析
- STL sort源码剖析
- 【转载】STL"源码"剖析-重点知识总结
- Java LinkedList源码剖析
- 源码剖析——ArrayList和LinkedList的区别
- SGI STL 空间配置器(allocator)源码剖析
- STL源码:list