STL 容器 -- list
list 介绍
有关list
的一些总结是:
list
是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代;list
的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素;list
与forward_list
非常相似:最主要的不同在于forward_list
是单链表,只能朝前迭代,已让其更简单高效;- 与其他的序列式容器相比(
array
,vector
,deque
),list
通常在任意位置进行插入、移除元素的执行效率更好; - 与其他序列式容器相比,
list
和forward_list
最大的缺陷是不支持任意位置的随机访问,比如:要访问list
的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list
还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list
来说这可能是一个重要的因素)。
图示 list 的结构
list
的结构如下图所示:
list 的接口
下面提几句一些 list
的接口:
1.list 的构造函数
2.list 迭代器(iterator)的使用
注意:反向迭代器,如果是从rbegin
开始,即对象的最后一位开始,其指针亦是自加运算,不是自减,比如
string s = "12345";
list<char> lst2(s.begin(), s.end());
list<char>::reverse_iterator rit = lst2.rbegin();
while (rit != lst2.rend())
{
cout << *rit << " ";
*rit = 'b';
rit++;
}cout << endl;
此处如果想用反向迭代器输出对象内容,则需从rend
开始,即对象的第一位开始,只不过一开始需要对迭代器指针自减一次,还需最后打印最后一位内容,如下
string s = "12345";
list<char> lst3(s.begin(), s.end());
list<char>::reverse_iterator rit2 = lst3.rend();
rit2--; //因为不自减会越界
while (rit2 != lst3.rbegin())
{
cout << *rit2 << " ";
*rit2 = 'b';
rit2--;
}
cout << *rit2 <<endl;//需要打印最后一位内容
产生以上的内容,主要是因为 list
自身结构如此,如图
在上图中,begin
与end
为正向迭代器,对迭代器执行++操作,迭代器向后移动;
rbegin
(相当于end
)与rend
(相当于begin
)为反向迭代器,对迭代器执行++操作,迭代器向前移动。
还需要注意的是,list
的begin()
返回的节点是头节点的下一个节点,end()
返回的节点是头节点!!!!!!
3.list的容量 capacity
4.list element access
5.list 的增删查改
6.list
的迭代器失效
迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。这与vector
和string
的迭代器失效有些许不同,因为list
的底层结构为带头结点的双向循环链表,因此在list
中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
在上一篇博客 C++ 之 vector 类中,因并未对 list
进行介绍,所以对 vector
和 list
的对比不太清晰,所以现在对这两种容器进行详细的对比说明:
vector
与list
都是STL
中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同用图表示如下: