3

I've been told that std::vector has a C-style array on the inside implementation, but would that not negate the entire purpose of having a dynamic container?

So is inserting a value in a vector an O(n) operation? Or is it O(1) like in a linked-list?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
Aposhian
  • 801
  • 1
  • 10
  • 27
  • The linked list class in C++ is `std::list`. Thus a `std::vector` is not a linked list -- it *is* basically a dynamic array and has insertion times no different than what you would expect (`O(n)`), unless inserted at the end of the sequence. http://stackoverflow.com/questions/181693/what-are-the-complexity-guarantees-of-the-standard-containers – PaulMcKenzie Jan 29 '16 at 21:49

2 Answers2

6

From the C++11 standard, in the "sequence containers" library section (emphasis mine):

[23.3.6.1 Class template vector overview][vector.overview]
A vector is a sequence container that supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency.

This does not defeat the purpose of dynamic size -- part of the point of vector is that not only is it very fast to access a single element, but scanning over the vector has very good memory locality because everything is tightly packed together. In practice, having good memory locality is very important because it greatly reduces cache misses, which has a large impact on runtime. This is a major advantage of vector over list in many situations, particularly those where you need to iterate over the entire container more often than you need to add or remove elements.

Chris Beck
  • 15,614
  • 4
  • 51
  • 87
3

The memory in a std::vector is required to be contiguous, so it's typically represented as an array.

Your question about the complexity of the operations on a std::vector is a good one - I remember wondering this myself when I first started programming. If you append an element to a std::vector, then it may have to perform a resize operation and copy over all the existing elements to a new array. This will take time O(n) in the worst case. However, the amortized cost of appending an element is O(1). By this, we mean that the total cost of any sequence of n appends to a std::vector is always O(n). The intuition behind this is that the std::vector usually overallocates space in its array, leaving a lot of free slots for elements to be inserted into without a reallocation. As a result, most of the appends will take time O(1) even though every now and then you'll have one that takes time O(n).

That said, the cost of performing an insertion elsewhere in a std::vector will be O(n), because you may have to shift everything down.

You also asked why this is, if it defeats the purpose of having a dynamic array. Even if the std::vector just acted like a managed array, it's still a win over raw arrays. The std::vector knows its size, can do bounds-checking (with at), is an actual object (unlike an array), and doesn't decay to a pointer. These extra features - coupled with the extra logic to make appends work quickly - are almost always worth it.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065