-1

We all know that std::vector::push_back has constant (amortized) complexity. It is constant because we say that the amortization cost is negligible, doubling every time. With reallocation being linear complexity.

Let's change our std::vector interface a bit to force reallocation in different fun ways.

Reallocate at every push_back

Is push_back still O(1) (amortized) if we reallocated on every push_back?

At every push_back we go through all the items in the vector I guess the constant part would drop here and both push_back and reallocation are O(N)

Reallocate only on odd numbered push_back

Is push_back still O(1) (amortized) if we reallocate on every other push_back?

Compared to the other variant, would push_back still be linear O(N)? Or can we still assume it's constant amortized?

Zeta
  • 103,620
  • 13
  • 194
  • 236
dau_sama
  • 4,247
  • 2
  • 23
  • 30

1 Answers1

1

In this case, would push_back still be constant?

No. It's O(realloc(n)), which is O(n).

In this case, would push_back still be linear O(N)?

Yes. It's best-case performance is O(1), it's worst case performance O(realloc(n)), which is O(n). If you call push_back N times, you will call realloc N/2 times, each using O(N), so on average we have O(N*(N/2)/N) = O(N/2) = O(N).

Compare that to the double-the-size push_back, where on N push_back's we will only call realloc log(N) times. See this post for a detailed explanation.

Zeta
  • 103,620
  • 13
  • 194
  • 236
  • thanks for the clear explanation! could you just elaborate quickly on why: `N*log(N)/N = 1 + log(N)/N` ? Wouldn't it be: `log(N)` with the two `N` being taken out? – dau_sama Feb 06 '18 at 17:39
  • 1
    Because I'm an idiot and misread my own code as `(N+log(N))/N`. – Zeta Feb 06 '18 at 17:42