STL之list源码剖析
来源:互联网 发布:越南人长相知乎 编辑:程序博客网 时间:2024/05/09 22:41
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 sorttemplate <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源码剖析---list
- STL源码剖析---list
- STL源码剖析---list
- STL源码剖析---list
- STL源码剖析---list
- STL源码剖析----list
- STL源码剖析---list
- 【STL】list源码剖析
- STL源码剖析—list
- STL源码剖析-list transfer()
- 《STL源码剖析》中的List
- STL源码剖析之List容器【2013.11.18】
- STL源码剖析——序列容器之list
- git 使用
- 导出通讯录
- IEC 61850 学习笔记
- TextBox Password Mode
- Eclipse插件之编码主题插件---Eclipse Color Theme
- STL之list源码剖析
- JS Replace 全部替换字符 用法
- java深复制和浅复制
- TCPDump介绍
- 12个最好的免费网站速度和性能测试工具
- 从奥特曼和小怪兽的决斗中分析java类和对象-初学者必须会的一个入门程序
- Oracle RAC 11gR2 环境下的连接管理
- 构造器,重载,this,传递
- qq登录界面及其实现