list介绍
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
- 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
- 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)
list的迭代器失效
迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
list<int>::iterator it = l.begin();
while(it != l.end())
{
if(*it % 2 == 0)
{
//l.erase(it)(错误)
//it++
//erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值
it = l.erase(it);
}
else //(正确)
{
++it;
}
//因为标准库的erase返回值是迭代器,而返回的迭代器是被删除元素的下一个迭代器.这样也就不会有野指针的问题了。
}
实现的接口
list节点类
struct ListNode
{
ListNode<T>* _prev;
ListNode<T>* _next;
T _val;
ListNode(const T& val = T())
: _val(val)
, _prev(nullptr)
, _next(nullptr)
{}
};
list迭代器类
//正向迭代器
template<class T, class Ref, class Ptr>
class ListIterator
{
typedef ListNode<T>* PNode;
typedef ListIterator<T, Ref, Ptr> Self;
public:
ListIterator(PNode pNode = nullptr);
ListIterator(const iterator& l);
Ref operator*();
Ptr* operator->();
iterator& operator++();
iteratoroperator++(int);
iterator& operator--();
iterator& operator--(int);
bool operator!=(const iterator& l);
bool operator==(const iterator& l);
private:
PNode _pNode;
};
//反向迭代器
template<class Iterator, class Ref, class Ptr>
struct reverse_ListIterator {
typedef reverse_ListIterator<Iterator, Ref, Ptr> reverse_iterator;
reverse_ListIterator(Iterator cur)
reverse_iterator& operator++()
reverse_iterator& operator--()
Ref operator*()
Ptr* operator->()
bool operator==(const reverse_iterator& l)
bool operator!=(const reverse_iterator& l)
Iterator _cur;
};
默认成员函数部分
list();
list(int n, const T& value = T());
template <class Iterator>
list(Iterator first, Iterator last);
list(const list<T>& l);
list<T>& operator=(const list<T> l);
~list();
迭代器部分
iterator begin();
iterator end();
const_iterator begin();
const_iterator end();
容量部分
size_t size()const;
bool empty()const;
访问部分
T& front();
const T& front()const;
T& back();
const T& back()const;
修改部分
void push_back(const T& val){insert(begin(), val);}
void pop_back(){erase(--end());}
void push_front(const T& val){insert(begin(), val);}
void pop_front(){erase(begin());}
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val);
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos);
void clear();
void swap(List<T>& l);
代码实现
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
namespace lc
{
// List的节点类
template<class T>
struct ListNode
{
ListNode<T>* _prev;
ListNode<T>* _next;
T _val;
ListNode(const T& val = T())
: _val(val)
, _prev(nullptr)
, _next(nullptr)
{}
};
//反向迭代器
template<class Iterator, class Ref, class Ptr>
struct reverse_ListIterator {
typedef reverse_ListIterator<Iterator, Ref, Ptr> reverse_iterator;
reverse_ListIterator(Iterator cur)
:_cur(cur)
{}
reverse_iterator& operator++() {
--_cur;
return *this;
}
reverse_iterator& operator--() {
++_cur;
return *this;
}
it++
//reverse_iterator& operator++(int) {
// auto tmp = *this;
// _cur--;
// return *tmp;;
//}
it--
//reverse_iterator& operator++(int) {
// auto tmp = *this;
// _cur++;
// return *this;
//}
Ref operator*() {
auto tmp = _cur;
--tmp;
return *tmp;
}
Ptr* operator->() {
return &(operator*());
}
bool operator==(const reverse_iterator& l) {
return _cur == l._cur;
}
bool operator!=(const reverse_iterator& l) {
return _cur != l._cur;
}
Iterator _cur;
};
//正向迭代器
template<class T, class Ref, class Ptr>
class ListIterator
{
typedef ListNode<T>* PNode;
typedef ListIterator<T, Ref, Ptr> iterator;
public:
ListIterator (PNode node = nullptr)
:_node(node)
{}
ListIterator (const iterator& l) {
_node = l._node;
}
Ref operator*() {
return _node->_val;
}
Ptr* operator->() {
return &(operator*());
}
//++it
iterator& operator++() {
_node = _node->_next;
return *this;
}
//it++
iterator& operator++(int) {
iterator tmp(*this);
_node = _node->_next;
return tmp;
}
//--it
iterator& operator--() {
_node = _node->_prev;
return *this;
}
iterator& operator--(int) {
iterator tmp(*this);
_node = _node->_prev;
return *this;
}
bool operator!=(const iterator& l) {
return _node != l._node;
}
//lt1 == lt2
bool operator==(const iterator& l) {
return _node == l._node;
}
PNode _node;
};
//list类
template<class T>
class list
{
typedef ListNode<T> Node;
typedef Node* PNode;
public:
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;
typedef reverse_ListIterator<iterator, T&, T*> reverse_iterator;
typedef reverse_ListIterator<const_iterator, const T&, const T*> const_reverse_iterator;
public:
//List的构造
list() {
CreateHead();
}
//构造的list中包含n个值为val的元素
list(int n, const T& value = T()) {
CreateHead();
while (n--) {
push_back(value);
}
}
template <class Iterator>
//list<int> lt1(lt.begin(), lt.end());
list(Iterator first, Iterator last) {
CreateHead();
while (first != last) {
push_back(*first);
first++;
}
}
//list<int> lt1(lt2)
list(const list<T>& l) {
CreateHead();
list<int> tmp(l.begin(), l.end());
this->swap(tmp);
//list(l.begin(), l.end());
}
//lt3 = lt2
list<T>& operator=(list<T> l) {
swap(l);
return *this;
}
~list() {
clear();
delete _head;
_head = nullptr;
}
reverse_iterator rbegin() {
return reverse_iterator(end());
}
reverse_iterator rend() {
return reverse_iterator(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);
}
size_t size() const{
size_t count = 0;
list<int>::const_iterator it = (*this).begin();
while (it != (*this).end()) {
count++;
it++;
}
return count;
}
bool empty() const{
return size() == 0;
}
T& front() {
return _head->_next->_val;
}
const T& front()const {
return _head->_next->_val;
}
T& back() {
return _head->_prev->_val;
}
const T& back()const {
return _head->_prev->_val;
}
void push_back(const T& val) {
//Node* cur = new Node(val);
//Node* prev = _head->_prev;
//prev->_next = cur;
//cur->_prev = prev;
//_head->_prev = cur;
//cur->_next = _head;
insert(end(), val);
}
void pop_back() {
erase(--end());
}
void push_front(const T& val) {
insert(begin(), val);
/* PNode cur = new Node(val);
_head->_next->_prev = cur;
cur->_next = _head->_next;
_head->_next = cur;
cur->_prev = _head;*/
}
void pop_front(){
//PNode next = _head->_next->_next;
//delete _head->_next;
//_head->_next = next;
//next->_prev = _head;
erase(begin());
}
// // 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val) {
PNode cur = new Node(val);
PNode prev = pos._node->_prev;
prev->_next = cur;
cur->_prev = prev;
cur->_next = pos._node;
pos._node->_prev = cur;
return iterator(cur);
}
// // 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos) {
assert(pos._node != _head);
PNode prev = pos._node->_prev;
PNode next = pos._node->_next;
prev->_next = next;
next->_prev = prev;
delete pos._node;
return iterator(next);
}
void clear() {
list<T>::iterator it = begin();
while (it != end()) {
it = erase(it);
}
}
// swap(lt2)
void swap(list<T>& l) {
std::swap(_head, l._head);
}
private:
void CreateHead() {
_head = new Node;
_head->_prev = _head;
_head->_next = _head;
}
PNode _head;
};
list与vector的对比
vector和数组类似,它拥有一段连续的内存空间,并且起始地址不变,因此它能非常好的支持随机存取(即使用[]操作符访问其中的元素),但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝(复杂度是O(n)),另外,当该数组后的内存空间不够时,需要重新申请一块足够大的内存并进行内存的拷贝。这些都大大影响了vector的效率。
list是由数据结构中的双向链表实现的,因此它的内存空间可以是不连续的。因此只能通过指针来进行数据的访问,这个特点使得它的随机存取变的非常没有效率,需要遍历中间的元素,搜索复杂度O(n),因此它没有提供[]操作符的重载。但由于链表的特点,它可以以很好的效率支持任意地方的删除和插入。