STL之list

来源:互联网 发布:淘宝千里眼数据准确吗 编辑:程序博客网 时间:2024/06/03 17:01

STL的List节点

STL的List节点结构如下

struct node{            T data;            node *prev;            node *next;            list<T> *container;    };

显然是List是一个双向链表。

STL的List迭代器

list不再像vector一样能以普通指针当做迭代器,因为其节点不保证在连续空间内,list的迭代器必须有能力指向list的结点,并有能力进行递增,递减,取值,成员存取等操作。
由于list是一个双向链表,迭代器必须具有前移和后移的能力,所以list提供的是Bidirectional Iterator.
list有个重要的性质:插入和接合操作都不会造成原有的list迭代器失效,这在vector是不成立的,因为vector的插入可能造成记忆体重新配置,导致原有的迭代器全部失效。甚至List的元素删除操作也只有指向被删除的那个迭代器失效,其他迭代器不受任何影响。
这里写图片描述

迭代器设计如下:

template<class T>    struct listIterator :public iterator<bidirectional_iterator_tag, T>{        template<class T>        friend class list;    public:        typedef node<T>* nodePtr;        nodePtr p;    public:        explicit listIterator(nodePtr ptr = nullptr) :p(ptr){}        listIterator& operator++(){            p=(nodeptr)(p->next);            return *this;        }        listIterator operator++(int){            self temp=*this;            ++*this;            return temp;        }        listIterator& operator --(){            p=(nodeptr)(p->prev);            return *this;        }        listIterator operator --(int){            self temp=*this;            --*this;            return temp;        }        T& operator *(){ return p->data; }        T* operator ->(){ return &(operator*()); }    };

list的数据结构

list不仅是双向链表还是一个环状双向链表,所以他需要一个指针,便可以完整表现整个链表。

template<class T,class Alloc=alloc>class list{    protect:        typedef _list_node<T> list_node;    public:        typdef list_node *link_type;    protect:        link_type node;//只要一个指针便可表示整个环状双向链表};

如果让指针node指向可以置于尾端的一个空白点,node便能符合STL“前闭后开”的区间要求,成为last迭代器,如下图
这里写图片描述
这样下面几个函数便可以轻易完成。

iterator begin(){return (link_type)((*node).next);}iterator end(){return node;}bool empty(){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());}

list的元素操作

list的插入操作和移除操作较为重要,再加上list的操作很多,所以只挑这两个来说。

//插入一个节点作为头节点void push_front(const T &x){insert(begin(),x);}//插入一个节点作为尾节点void push_back(const T &x){insert(end(),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);    return iterator(next_node);}//移除头节点void pop_front(){erase(begin());}//移除尾节点void pop_back(){    iterator temp=end();    earse(--temp);}//清除所有节点template<class T,class Alloc>void list<T,Alloc>::clear(){    link_type cur=(link_type)node->next;//begin()    while(cur!=node){        link_type temp=cur;        cur=cur->next;        destroy_node(temp);    }    node->prev=node;    node->next=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==value)erase(first);        first=next;    }}

list内部提供一个所谓的迁移操作(transfer),将某连续范围内的元素迁移到某个特定位置前。

//将[first,last)内的所有元素移动到position前void transfer(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 temp=link_type((*position.node).prev);        (*position.node).prev=(*last.node).prev;        (*last.node).prev=(*first.node).prev;        (*first.node).prev=temp;    }}

这里写图片描述

原创粉丝点击