list的底层是双向循环列表,每个节点包含:
数据域:存储元素值。
前驱指针(prev):指向前一个节点。
后继指针(next):指向后一个节点
特点:
节点在内存中不连续,通过指针链接
任意位置插入 / 删除只需修改指针(时间复杂度 O(1))
list的构造与初始化
cpp
#include<list>
#include<iostream>
void test()
{
list<int> l1;//构造无参空list
list<int> l2(5,10);
//用迭代器范围初始化(拷贝其他容器元素)
list<int> l3(v.begin(),v.end());
list<int> l4<l3>;
}
list iterator的使用
begin+end
begin指向第一个元素的迭代器,end指向最后一个位置的下一个位置的迭代器,作为迭代的结束标志。
cpp
for(list<int>::iterator it=l.begin;it!=end();it++)
{
*it*=2;
}
rbegin+rend
rebegin指向最后一个元素的反向迭代器,rend指向第一个元素的前一个位置的反向迭代器。
cpp
for (list<int>::reverse_iterator rit = l.rbegin(); rit != l.rend(); ++rit)
{
cout << *rit << " ";
}
list capacity
empty
检测list是否为空,如果为空,返回true,否则返回false。
size
返回list当中有效节点的个数
cpp
cout<<l.size()<<endl;
list element access
front
返回list当中第一个结点值的引用
back
功能:返回 list 的最后一个节点中值的引用。
cpp
cout<<l.front()<<endl;
cout<<l.back()<<endl;
list modifiers
push_front
在list首元素前插入值为val的元素
cpp
l.push_front(1);
pop_front
在list首元素前删除值
cpp
l.pop_front(1);
push_back
在 list 尾部插入值为 val 的元素
pop_back
在list尾部插入值为val的元素
insert
在list的目标位置插入值为val的元素
cpp
l.insert(it,3);
erase
在list中删除值为val的元素
cpp
auto it=l.begin();
++it;
++it;
l.erase(it);
swap
交换两个list的元素
cpp
l1.swap(l2);
clear
清除list当中的有效元素
cpp
l.clear();
list的迭代器失效
list是双向循环列表,节点在内存当中不连续。因此:
1插入操作不会导致迭代器失效
2删除操作仅被删除的节点的迭代器删除,其他节点迭代器不受影响
错误的示例:
cpp
void test()
{
int array[]={1,2,3,4};
list<int> l(array,array+sizeof(array)/sizeof(array[0]);
auto it=l.begin();
while(it!=l.end())
{
l.erase(it);
++it;//对失效的迭代器自增,是未定义行为
}
}
正确代码:
cpp
l.erase(it++);//
原因:
it是用后自增,会先返回it的当前值,用于删除erase当前值,然后自动移动到下一个节点,避免使用失效的迭代器。
也可以显式使用erase的返回值更新:
cpp
it=l.erase(it);
list的反向迭代器
反向迭代器的核心设计就是内部有一个正向迭代器_it。通过对正向迭代器的操作进行反转:
反向迭代器的++相当于反向迭代器的--;
反向迭代器的--相当于正向的++;
反向迭代器解引用时*访问的是正向迭代器前一个位置的元素。