list这个迭代器是双向迭代器,与vector的迭代器具有很大的区别,主要在于双向迭代器不支持+- 操作
正由于list的双向迭代器,因此<algorithm>
中的sort()
函数无法使用,list单独实现了一个sort()函数,但效率极低。
一、list的介绍与使用
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向
其前一个元素和后一个元素。 - list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高
效。 - 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
- 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list
的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间
开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这
可能是一个重要的因素)
二、list的模拟实现
2.1 节点类
//结点
template<class T>
struct ListNode
{T _data;ListNode<T>* _prev;ListNode<T>* _next;ListNode(const T& x=T()):_prev(nullptr),_next(nullptr),_data(x){}
};
2.2 迭代器类
由于在遍历时需要实现++的操作,但是链表并不是连续的,因此需要对结点的行为进行重新定义,就有了这个类
//迭代器template<class T,class ref,class ptr>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator self;Node* _node;ListIterator(Node* node):_node(node){}self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prev;return *this;}self& operator++(int){Node* temp = *this;_node = _node->_next;return temp;}self& operator--(int){Node* temp = *this;_node = _node->_prev;return temp;}bool operator!=(const self& x){return _node != x._node;}bool operator==(const self& x){return _node == x._node;}ref operator*(){return _node->_data;}ptr operator->(){return &_node->_data;}};
2.3 list类
//链表
template<class T>
class list
{typedef ListNode<T> Node;typedef ListIterator<T,T&,T*> iterator;typedef ListIterator<T,const T&,const T*> const_iterator;
private:Node* _head;
public:void empty_head(){_head = new Node();_head->_next = _head;_head->_prev = _head;}list(){empty_head();}list(const list& lt){empty_head();for (const auto& e : lt){push_back(e);}}list(initializer_list<T> il){empty_head();for (const auto& e : il){push_back(e);}}list<T>& operator=(list<T> lt){swap(_head, lt._head);return *this;}void clear(){auto it = begin();while (it != end()){it=erase(it);//连续的删除,可能造成迭代器失效}}~list(){clear();delete _head;_head = nullptr;}void push_back(const T& x){/*Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;*/insert(end(), x);}void pop_back(){erase(--end());}void push_front(const T& x){insert(begin(), x);}void pop_front(){erase(begin());}iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);newnode->_prev = prev;prev->_next = newnode;cur->_prev = newnode;newnode->_next = cur;return iterator(newnode);}iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;return next;}
};