我被告知std :: vector在内部实现上有一个C风格的数组,但这不会否定拥有动态容器的整个目的吗?
那么在向量中插入一个O(n)运算的值吗?或者是链接列表中的O(1)吗?
答案 0 :(得分:5)
从C ++ 11标准,在"序列容器"图书馆部分(强调我的):
[23.3.6.1班级模板
vector
概述] [vector.overview]
向量是一个序列容器,支持(分期)常量时插入和擦除操作 结束; 在中间插入和擦除需要线性时间。但是,存储管理是自动处理的 提示可以提高效率。
这并没有破坏动态大小的目的 - 向量点的一部分不仅是访问单个元素非常快,而且在向量上扫描具有非常好的内存位置因为一切都紧紧地挤在一起。在实践中,具有良好的内存局部性非常重要,因为它极大地减少了缓存未命中,这对运行时有很大影响。在许多情况下,这是vector
优于list
的一个主要优势,特别是那些需要比需要添加或删除元素更频繁地遍历整个容器的那些优势。
答案 1 :(得分:2)
std::vector
中的内存必须是连续的,因此它通常表示为数组。
关于std::vector
操作复杂性的问题是一个很好的问题 - 我记得在我第一次开始编程时自己想知道这个问题。如果将元素追加到std::vector
,则可能必须执行调整大小操作并将所有现有元素复制到新数组。在最坏的情况下,这将花费时间O(n)。但是,附加元素的amortized cost是O(1)。这样,我们的意思是任何序列的n附加到std::vector
的总成本总是为O(n)。这背后的直觉是std::vector
通常在其数组中分配空间,留下大量空闲插槽,以便在不重新分配的情况下插入元素。结果,大多数追加都需要花费时间O(1),即使你偶尔会有一个需要时间O(n)的追加。
也就是说,在std::vector
的其他位置执行插入操作的成本将为O(n),因为您可能需要将所有内容都降低。
你也问过为什么会这样,如果它失去了拥有动态数组的目的。即使std::vector
只是像托管数组一样,它仍然是对原始数组的胜利。 std::vector
知道它的大小,可以进行边界检查(使用at
),是一个实际的对象(与数组不同),并且不会衰减到指针。这些额外的功能 - 加上额外的逻辑,使附加工作迅速 - 几乎总是值得的。