目录
1 list的介绍
- 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- 2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- 3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
- 4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
- 5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)
2 list的使用
list
中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为
list
中一些
常见的重要接口:
2.1 list的构造
构造函数
|
接口说明
|
list (size_type n, const value_type& val = value_type())
|
构造的
list
中包含
n
个值为
val
的元素
|
list()
|
构造空的
list
|
list (const list& x)
|
拷贝构造函数
|
list (InputIterator fifirst, InputIterator last)
|
用
[fifirst, last)
区间中的元素构造
list
|
2.2 list iterator的使用
此处,大家可暂时将迭代器理解成一个指针(不是原生指针,而是一个被封装了的指针),该指针指向list中的某个节点。
用法基本与string和vector类似:
函数声明
|
接口说明
|
begin
+
end
|
返回第一个元素的迭代器
+
返回最后一个元素下一个位置的迭代器
|
rbegin
+
rend
|
返回第一个元素的
reverse_iterator,
即
end
位置
,
返回最后一个元素下一个位置的reverse_iterator,
即
begin
位置
|
【注意】
1. begin 与 end 为正向迭代器,对迭代器执行 ++ 操作,迭代器向后移动 (左闭右开)2. rbegin(end) 与 rend(begin) 为反向迭代器,对迭代器执行 ++操作,迭代器向前移动 (左开右闭)
2.3 list capacity
函数声明
|
接口说明
|
empty
|
检测
list
是否为空,是返回
true
,否则返回
false
|
size
|
返回
list
中有效节点的个数
|
2.4 list element access
函数声明
|
接口说明 |
front
|
返回list的第一个节点中值的引用 |
back
|
返回list的最后一个节点中值的引用 |
2.5 list modififiers
函数声明
|
接口说明 |
push_front
|
在list首元素前插入值为val的元素 |
pop_front
|
删除list中第一个元素 |
push_back
|
在list尾部插入值为val的元素 |
pop_back
|
删除list中最后一个元素 |
insert
|
在list position 位置中插入值为val的元素 |
erase
|
删除list position位置的元素 |
swap
|
交换两个list中的元素 |
clear
|
清空list中的有效元素 |
assign | 开空间并且初始化 |
演示代码:
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<int> ls;
ls.assign(5, 6);
for (auto& e : ls)
cout << e << " ";
return 0;
}
结果:
2.6 Operations:
接合。 |
C++98:
entire list (1) void splice (iterator position, list& x);single element (2) void splice (iterator position, list& x, iterator i);element range (3) void splice (iterator position, list& x, iterator first, iterator last);
这个函数有些情况下很好用,将某段迭代器区间接合到另外一个链表中:
int main()
{
list<int> ls1;
ls1.push_back(1);
ls1.push_back(2);
ls1.push_back(3);
ls1.push_back(4);
list<int> ls2;
ls2.push_back(10);
ls2.push_back(20);
ls2.push_back(30);
ls2.push_back(40);
auto it1 = ls1.begin();
++it1;
++it1;
ls1.splice(it1, ls2);
cout << "list1:";
for (auto& e : ls1)
cout << e << " ";
cout << endl;
cout << "list2:";
for (auto& e : ls2)
cout << e << " ";
return 0;
}
当我们运行结果时:
不难发现结合会直接将另外一个链表的结点直接给链接过来。
还有一些其他的成员函数大家可以自行到官方库中查询,里面介绍的很详细。
3 list与vector的对比
vector
与
list
都是
STL
中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不
同,其主要不同如下:
vector
|
list
|
|
底
层
结
构
|
动态顺序表,一段连续空间
|
带头结点的双向循环链表
|
随
机
访
问
|
支持随机访问,访问某个元素效率
O(1)
|
不支持随机访问,访问某个元素
效率
O(N)
|
插
入
和
删
除
|
任意位置插入和删除效率低,需要搬移元素,时间复杂度为
O(N)
,插入时有可能需要增容,增容:开辟新空
间,拷贝元素,释放旧空间,导致效率更低,增容还有可能造成空间浪费
|
任意位置插入和删除效率高,不
需要搬移元素,时间复杂度为
O(1)
|
空
间
利
用
率
|
底层为连续空间,不容易造成内存碎片,空间利用率
高,缓存利用率高
|
底层节点动态开辟,小节点容易
造成内存碎片,空间利用率低,缓存利用率低
|
迭
代
器
|
原生态指针
|
对原生态指针
(
节点指针
)
进行封装
|
迭
代
器
失
效
|
在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删
除时,当前迭代器需要重新赋值否则会失效
|
插入元素不会导致迭代器失效,
删除元素时,只会导致当前迭代器失效,其他迭代器不受影响
|
使
用
场
景
|
需要高效存储,支持随机访问,不关心插入删除效率
|
大量插入和删除操作,不关心随
机访问
|