1.概述
List使用一個doubly linked list(雙向對列)來儲存元素,相較於Vector的線性空間,List就顯的複雜的多,它的好處是每次插入或刪除一個元素,就配置或釋放一個元素空間。對於任何位置的元素的插入或刪除,List永遠是常數時間。
2.list的節點
list本身和list節點是不同的結構,需要分開設計。以下是STL list的節點(node)結構:
template <class T>
struct __list_node{
typedef void* void_pointer;
void_pointer prev;
void_pointer next;
T data;
}
3.list的迭代器
由於STL List是一個雙向連結串列,迭代器必須具備前移、後移的能力,所以list提供的是Bidirectional Iterators
list 有一個重要的性質:插入操作(insert)和接合操作(splice)都不會造成原有list迭代器失效。這在vector是不成立的,因為vector的插入操作可能會造成空間的重新配置,導致原有迭代器的全部失效。甚至list的刪除(erase)操作也只有“指向被刪除元素”的那個迭代器失效,其他迭代器不收任何影響。
以下是list迭代器的設計:(只列出部分)
template<class T,class Ref,class Ptr>
struct __list_iterator{
typedef __list_iterator<T,T&,T*> iterator;
typedef __list_iterator<T,Ref,Ptr> self;
typedef bidirectioanal_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref referrence;
typedef __list_node<T>* link_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
link_type node;
__list_iterator(link_type x):node(x);
__list_iterator(){}
__list_iterator(const iterator& x):node(x.node){}
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;
}
}
4.list的資料結構
SGI list 不僅是一個雙向連結串列,而且還是一個環裝雙向連結串列。所以它只需要一個指標,便可以完整表現整個連結串列:
template <class T,class alloc=Alloc>
class list{
protected:
typedef list_node<T> node;
public:
typedef list_node* link_type;
protected:
link_type node;
}
iterator begin(){ return (link_type)((node*).next);} //return link_type,使用iterator(link_type)建構函式返回一個iterator;
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;
}
reference front() {return *begin()}
reference back() {return *(--end())}
5.list的構造與記憶體管理
list預設使用alloc作為空間配置器,並據此另外定義了一個list_node_allocator.
template <class T,class Alloc=alloc>
class list{
protected:
typedef __list_node<T> list_node;
typedef simple_alloc<list_node,Alloc> list_node_allocator;
}
list_node_allocator(n)表示配置n個節點空間。以下四個函式分別用來配置、釋放、構造、銷燬一個節點:
protected:
//配置一個節點並傳回
link_type get_node() {return list_node_allocator::allocate();}
//釋放一個節點
void put_node(lingk_type p){ list_node_allocator::deallocate();}
//產生(配置並構造)一個節點,帶有元素值
link_type create_node(const T& x){
link_type p=get_node();
construct(&p->data,x);
retrurn p;
}
//銷燬(析構並釋放)一個節點
void destroy_node(link_type p){
destory(&p->data);
put_data(p);
}
public:
list(){ empty_initialize(); }
protected:
void empty_initialize(){
node=get_node();
node_next=node;
node_prev=node;
}
void push_back(const T&) {insert(end(),x);}
iterator insert(iterator position,const T& x){
link_type tmp=create_node(x);//產生一個節點;
tmp->next=position.node;
tmp->prev=position.node->prev;
(link_type(psition.node->prev))->next=tmp;
postion.node->prev=tmp;
return tmp;
}
6.list的元素操作
void push_back(const T& x){insert(end(),x);}
void psuh_pront(const T& x){insert(begin(),x);}
//移除迭代器position所指節點
iterator erase(iterator position){
link_type next_node=link_type(position.node->next);
link_type prev_node=link_type(position.node->prev);
prev_node->next=next_node;
next_node->prev=prev_node;
destroy_node(position.node);
return iterator(next_node);
}
//移除頭結點
void pop_front() { erase(begin());}
//移除尾節點
void pop_back(){
iterator tmp=end();
erase(--tmp);
}
//清除所有節點(整個連結串列)
template<class T,class Alloc>
void list<T,Alloc>::clear(){
link_type cur=(link_type)node->next;
while(cur!=node){
link_type tmp=cur;
cur=(link_type)cur->next;
destroy(tmp);
}
node->next=node;
node->prev=node;
}
//將數值為value的所有元素移除
template <class T,class Alloc>
void list<T,Alloc>::remove(const T& value){
iterator first=begin();
iterator last=end();
while(first!=last){
iterator next = first;
++next;
if(*first==next) erase(first);
first=next;
}
}
//移除數值相同的連續元素
template <class T,class Alloc>
void list<T,Alloc>::unique(){
iterator first=begin();
iterator last=end();
if(first == last) return;
iterator next=first;
while(++next != last){
if(*first == *next)
erase(next);
else
first=next;
next=first;
}
}