【问题标题】:Does the std::vector implementation use an internal array or linked list or other?std::vector 实现是否使用内部数组或链表或其他?
【发布时间】:2016-01-29 21:42:28
【问题描述】:
有人告诉我 std::vector 在内部实现中有一个 C 风格的数组,但这不会否定拥有动态容器的全部目的吗?
那么在向量中插入一个值是 O(n) 操作吗?还是像链表一样是 O(1)?
【问题讨论】:
标签:
c++
arrays
vector
stl
time-complexity
【解决方案1】:
来自 C++11 标准,在“序列容器”库部分(重点是我的):
[23.3.6.1 类模板vectoroverview][vector.overview]
向量是一个序列容器,它支持(摊销的)恒定时间插入和擦除操作
结尾; 在中间插入和擦除需要线性时间。不过,存储管理是自动处理的
可以给出提示以提高效率。
这并没有违背动态大小的目的——向量的部分意义在于不仅访问单个元素非常快,而且扫描向量具有非常好的内存局部性 因为一切都紧紧地挤在一起。在实践中,具有良好的内存局部性非常重要,因为它大大减少了缓存未命中,这对运行时有很大影响。这是vector 在许多情况下优于list 的主要优势,尤其是在您需要更频繁地迭代整个容器而不是添加或删除元素的情况下。
【解决方案2】:
std::vector 中的内存要求是连续的,因此它通常表示为一个数组。
您对std::vector 上的操作的复杂性提出了一个很好的问题——我记得当我第一次开始编程时,我自己也想过这个问题。如果将元素附加到std::vector,则它可能必须执行调整大小操作并将所有现有元素复制到新数组中。在最坏的情况下,这将花费时间 O(n)。但是,附加元素的amortized cost 是 O(1)。这样,我们的意思是 any 序列的 n 附加到 std::vector 的总成本总是 O(n)。这背后的直觉是std::vector 通常在其数组中过度分配空间,留下大量空闲槽供元素插入而无需重新分配。因此,大多数追加将花费时间 O(1),即使您时不时会有一个花费时间 O(n) 的追加。
也就是说,在 std::vector 的其他地方执行插入的成本将是 O(n),因为您可能必须将所有内容向下移动。
您还问为什么会这样,如果它违背了拥有动态数组的目的。即使std::vector 就像一个托管数组,它仍然是对原始数组的胜利。 std::vector 知道它的大小,可以进行边界检查(使用at),是一个实际对象(与数组不同),并且不会衰减为指针。这些额外的功能——再加上额外的逻辑让追加工作快速——几乎总是值得的。