list的底层是双向循环链表,可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代,与其他底层是顺序表的容器(vector,array,deque)相比,list在任意位置进行插入,移除元素更加高效;但是和这些底层是顺序表的容器相比,list最大的缺陷就是不支持任意位置的随机访问。
public:
Node* node;
list的成员变量只有一个节点类型的指针,它指向该双向循环链表的虚拟头节点。
//无参构造函数
list()
{
head = new Node();
head->next = head;
head->prev = head;
}
//利用模板函数以及迭代器来构造对象
template
list(Inputiterator first, Inputiterator last)
{
head = new Node();
head->next = head;
head->prev = head;
while (first != last)
{
push_back(*first);
++first;
}
}
//深拷贝的拷贝构造函数,现代写法
list(const list& x)
{
head = new Node();
head->next = head;
head->prev = head;
list tmp(x.begin(), x.end());
std::swap(head, tmp.head);
}
//取头节点的迭代器
iterator begin()
{
return iterator(head->next);
}
const_iterator begin() const
{
return const_iterator(head->next);
}
//以最后一个元素的下一个位置的迭代器构造的_revese_iterator作为返回值,就是用正向迭代器模拟实现反向迭代器,这是一种复用的表现,可以减少代码量
_revese_iterator rbegin()
{
return _revese_iterator(end());
}
const_reverse_iterator rbegin() const
{
return const_reverse_iterator(end());
}
//取尾节点(虚拟头节点)的迭代器
iterator end()
{
return iterator(head);
}
const_iterator end() const
{
return const_iterator(head);
}
//以第一个元素的迭代器构造的_revese_iterator作为返回值,就是用正向迭代器模拟实现反向迭代器,这是一种复用的表现,可以减少代码量
_revese_iterator rend()
{
return _revese_iterator(begin());
}
const_reverse_iterator rend() const
{
return const_reverse_iterator(begin());
}
上面的_reverse_iterator反向迭代器是由正向迭代器构造实现的,这是一种设计模式,是一种复用的表现,可以减少代码量。
利用List对象里的节点构造出迭代器,然后就可以使用该迭代器来遍历List对象中的每一个节点,实现解引用迭代器对象来完成取节点中的值的操作,还可以通过++,--来实现List对象中节点的遍历,list类迭代器本质上也是一个类,一个可以完成List对象中节点遍历的类。
list的成员变量只有一个节点类型的指针,它指向该双向循环链表的虚拟头节点。
public:
Node* node;
template
class __list_iterator
{
public:
typedef ListNode Node;
typedef __list_iterator self;
__list_iterator(Node* x)
:node(x)
{
}
//解引用运算符重载
Ref operator*()
{
return node->data;
}
//-> 迭代器是借助节点的指针访问修改链表,这里表示用指针->->来获取数据,然后编译器会优化为指针->来获取数据
Ptr operator->()
{
return &node->data;
}
//迭代器前置加加,返回加加后的迭代器
self operator++()
{
node = node->next;
return *this;
}
//迭代器后置加加,返回加加前的迭代器
self operator++(int)
{
self tmp(node);
node = node->next;
return tmp;
}
//迭代器前置减减,返回减减后的迭代器
self operator--()
{
node = node->prev;
return *this;
}
//迭代器后置减减,返回减减前的迭代器
self operator--(int)
{
self tmp(node);
node = node->prev;
return tmp;
}
//判断两个迭代器指向的内容是否相等
bool operator!=(const self& it) const
{
if (it.node != node)
{
return true;
}
return false;
}
bool operator==(const self& it) const
{
return !(*this != it);
}
public:
Node* node;
};
它的作用是可以反向遍历List里面的每一个节点,它是由正向迭代器构造出来的,所以它所有功能都是由正向迭代器来实现的,与正向迭代器不同的是,当解引用反向迭代器的时候,取得不是当前迭代器指向的节点的值,而是取得是前一个节点的值,这是因为迭代器rend指向的是头节点,迭代器rbegin指向的是虚拟头节点。反向迭代器的--,和++操作,对应着正向迭代器的++,--操作。
public:
_iterator it;
是一个正向迭代器
template
class resverse_iterator
{
public:
typedef iterator _iterator;
typedef resverse_iterator self;
resverse_iterator(const _iterator& x)
:it(x)
{
}
//解引用运算符重载
Ref operator*()
{
_iterator prev = it;
return *(--prev);
}
//-> 迭代器是借助节点的指针访问修改链表,这里表示用指针->->来获取数据,然后编译器会优化为指针->来获取数据
Ptr operator->()
{
_iterator prev = it;
--prev;
return &*(prev);
}
//迭代器前置加加,返回加加后的迭代器
self operator++()
{
--it;
return *this;
}
//迭代器后置加加,返回加加前的迭代器
self operator++(int)
{
self tmp(it);
--it;
return tmp;
}
//迭代器前置减减,返回减减后的迭代器
self operator--()
{
++it;
return *this;
}
//迭代器后置减减,返回减减前的迭代器
self operator--(int)
{
self tmp(it);
++it;
return tmp;
}
//判断两个迭代器指向的内容是否相等
bool operator!=(const self& It) const
{
return it != It.it;
}
bool operator==(const self& It) const
{
return !(it != It.it);
}
public:
_iterator it;
};
在List链表中尾插一个节点
无返回值
(1)先在堆上申请一块空间,这块空间存放着一个新节点的值
(2)让虚拟头节点的prev指针指向新节点,尾节点的next指针指向新节点
(3)新节点的prev指向尾节点,新节点的next指向虚拟头节点
//尾插一个元素
void push_back(const T& val)
{
Node* newnode = new Node(val);
Node* _prev = head->prev;
_prev->next = newnode;
newnode->prev = _prev;
newnode->next = head;
head->prev = newnode;
}
删除List对象中某个迭代器指向的节点,它可以是复用实现尾删,头删,以及清空List对象全部有效节点等功能
返回下一个节点的迭代器
(1)要删除的节点的前一个节点指向要删除的节点的下一个节点
(2)释放要删除的节点的空间
// 这里erase以后,pos是否失效?一定失效
iterator erase(iterator pos)
{
assert(pos != end());
Node* cur = pos.node;
Node* pre = pos.node->prev;
Node* _next = pos.node->next;
pre->next = _next;
_next->prev = pre;
delete cur;
iterator(_next);
}
//尾删一个元素
void pop_back()
{
erase(--end());
}
//头删一个元素
void pop_front()
{
erase(begin());
}
void clear()
{
//第一种方式:
//list::iterator it = begin();
//while (it != end())
//{
// iterator del = it++;
// delete del.node;
//}
//head->next = head;
//head->prev = head;
另一种方式
while (it != end())
{
erase(it++);
}
}
在迭代器pos指向的节点后面插入一个节点
返回插入的新节点的迭代器
(1)先在堆上申请一块空间,这块空间存放着一个新节点的值
(2)让迭代器pos指向的节点的prev指针指向新节点,迭代器pos指向的节点的前一个节点的next指针指向新节点
(3)新节点的prev指向迭代器pos指向的节点的前一个节点,新节点的next指向迭代器pos指向的节点
// 这里insert以后,pos是否失效?一定失效
iterator insert(iterator pos, const T& x)
{
Node* newnode = new Node(x);
Node* _prev = pos.node->prev;
_prev->next = newnode;
newnode->prev = _prev;
newnode->next = pos.node;
pos.node->prev = newnode;
return iterator(newnode);
}