Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the time complexity of python's list.append() method O(1)?

As seen in the documentation for TimeComplexity, Python's list type is implemented is using an array.

So if an array is being used and we do a few appends, eventually you will have to reallocate space and copy all the information to the new space.
After all that, how can it be O(1) worst case ?

like image 894
ohad edelstain Avatar asked Oct 09 '15 18:10

ohad edelstain


People also ask

What are the time complexity of a append 1?

Time Complexity: Append has constant time complexity i.e.,O(1).

What is the time complexity of list in Python?

Here is the summary for in : list - Average: O(n) set/dict - Average: O(1), Worst: O(n)

What is the time complexity of list insert Python?

According to Python's official Time Complexity page1, using list. insert always has O(n) (linear) complexity. Also, a Python list is not exactly the same as a C++ list. In fact, a Python list is more comparable to a C++ std::vector if anything.

How append () and extend () are different with reference to list in Python?

Python append() method adds an element to a list, and the extend() method concatenates the first list with another list (or another iterable). When append() method adds its argument as a single element to the end of a list, the length of the list itself will increase by one.


2 Answers

It's amortized O(1), not O(1).

Let's say the list reserved size is 8 elements and it doubles in size when space runs out. You want to push 50 elements.

The first 8 elements push in O(1). The nineth triggers reallocation and 8 copies, followed by an O(1) push. The next 7 push in O(1). The seventeenth triggers reallocation and 16 copies, followed by an O(1) push. The next 15 push in O(1). The thirty-third triggers reallocation and 32 copies, followed by an O(1) push. The next 17 push in O(1).

So all of the pushes have O(1) complexity, we had 56 copies at O(1), and 3 reallocations at O(n), with n = 8, 16, and 32. Note that this is a geometric series and asymptotically equals O(n) with n = the final size of the list. That means the whole operation of pushing n objects onto the list is O(n). If we amortize that per element, it's O(n)/n = O(1).

like image 125
rlbond Avatar answered Sep 29 '22 20:09

rlbond


If you look at the footnote in the document you linked, you can see that they include a caveat:

These operations rely on the "Amortized" part of "Amortized Worst Case". Individual actions may take surprisingly long, depending on the history of the container.

Using amortized analysis, even if we have to occasionally perform expensive operations, we can get a lower bound on the 'average' cost of operations when you consider them as a sequence, instead of individually.

So, any individual operation could be very expensive - O(n) or O(n^2) or something even bigger - but since we know these operations are rare, we guarantee that a sequence of O(n) operations can be done in O(n) time.

like image 44
Jacob Ritchie Avatar answered Sep 29 '22 19:09

Jacob Ritchie