根据这两个的不同整理了一张表供各位食用:
vector
与
list
都是
STL
中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下:
vector | list | |
底层结构 |
动态顺序表,一段连续空间
|
带头结点的双向循环链表
|
随机访问 |
支持随机访问,访问某个元素效率
O(1)
|
不支持随机访问,访问某个元素
效率
O(N)
|
插入和删除 |
任意位置插入和删除效率低,需要搬移元素,时间复杂
度为
O(N)
,插入时有可能需要增容,增容:开辟新空
间,拷贝元素,释放旧空间,导致效率更低
|
任意位置插入和删除效率高,不
需要搬移元素,时间复杂度为
O(1)
|
空间利用率 |
底层为连续空间,不容易造成内存碎片,空间利用率
高,缓存利用率高
|
底层节点动态开辟,小节点容易
造成内存碎片,空间利用率低,
缓存利用率低
|
迭代器 |
原生态指针
|
对原生态指针
(
节点指针
)
进行封装
|
迭代器失效 |
在插入元素时,要给所有的迭代器重新赋值,因为插入
元素有可能会导致重新扩容,致使原来迭代器失效,删
除时,当前迭代器需要重新赋值否则会失效
|
插入元素不会导致迭代器失效,
删除元素时,只会导致当前迭代
器失效,其他迭代器不受影响
|
使用场景 |
需要高效存储,支持随机访问,不关心插入删除效率
|
大量插入和删除操作,不关心随
机访问
|
也有文字供大家再次理解
1. 底层实现
-
std::vector
:- 底层实现:
std::vector
是一个动态数组,内存是连续分配的。 - 存储方式:它使用一块连续的内存来存储元素,这使得元素访问(通过索引)非常高效。
- 底层实现:
-
std::list
:- 底层实现:
std::list
是一个双向链表,内存分配是分散的。 - 存储方式:它由一系列节点组成,每个节点包含元素及指向前后节点的指针。节点在内存中不需要连续。
- 底层实现:
2. 元素访问
-
std::vector
:- 随机访问:支持常数时间的随机访问(通过索引),即
vector[i]
是 O(1) 的操作。 - 访问方式:适合需要频繁访问元素的场景。
- 随机访问:支持常数时间的随机访问(通过索引),即
-
std::list
:- 线性访问:不支持随机访问,只能通过迭代器进行线性访问,即 O(n) 的操作。
- 访问方式:适合需要频繁插入和删除操作的场景。
3. 插入和删除
-
std::vector
:- 插入/删除:在中间或开头插入或删除元素的效率较低,特别是对于大数据集,因为可能需要移动元素。尾部插入通常是 O(1) 操作(如果没有触发扩容)。
-
std::list
:- 插入/删除:在任意位置插入或删除元素的效率较高,因为只需更新相邻节点的指针,操作是 O(1) 的。但需要一个 O(n) 的时间来找到位置。
4. 内存管理
-
std::vector
:- 内存管理:由于使用连续内存,可能会因扩容而重新分配内存,可能会导致内存碎片问题。扩容时,所有元素都需要被复制到新的内存位置。
-
std::list
:- 内存管理:由于内存分配是分散的,避免了内存碎片问题,但每个节点有额外的指针开销。
5. 性能考虑
-
std::vector
:- 适用于需要高效的随机访问和在尾部插入/删除的情况。
- 适合用作数组的替代品。
-
std::list
:- 适用于频繁插入和删除操作,尤其是在列表的中间部分。
- 不适合需要随机访问的操作,因为访问时间较长。
总结
- 使用
std::vector
:当你需要高效的随机访问,并且在容器的末尾插入/删除元素时,std::vector
是一个更好的选择。 - 使用
std::list
:当你需要在容器的任意位置高效地插入/删除元素,而不关心随机访问的性能时,std::list
是一个更合适的选择。