Reputation: 1628
Long time ago I watched a video lecture from the Princeton Coursera MOOC: Introduction to algorithms, which can be found here. It explains the cost of resizing an ArrayList
like structure while adding or removing the elements from it. It turns out that if we want to supply resizing to our data structure we will go from O(n)
to amortized O(n)
for add
and remove
operations.
I have been using Java ArrayList
for a couple of years. I've been always sure that they grow and shrink automatically. Only recently, to my great surprise, I was proven wrong in this post. Java ArrayList
s do not shrink (even though, of course they do grow) automatically.
Here are my questions:
In my opinion providing shrinking in ArrayList
s does not make any harm as the performance is already amortized O(n)
. Why did Java creators did not include this feature into the design?
I know that other data structures like HashMap
s also do not shrink automatically. Is there any other data structure in Java which is build on top of arrays that supports automatic shrinking?
What are the tendencies in other languages? How does automatic shrinking look like in case of lists, dictionaries, maps, sets in Python/C# etc. If they go in the opposite direction to what Java does, then my question is: why?
Upvotes: 11
Views: 6801
Reputation: 71
Although arraylist with shrinking is still amortized O(n) time complexity, it involves more operation.
By shrinking you just save some memory space by adding some calculation, which is not a wise decision because the Moore's law says computer space double every 2 years. So the time is more valuable in algorithm than space.
Upvotes: 0
Reputation: 1705
Another issue with automatic shrinking is that you could get into really horrible 'pathological' situations where each insert and delete to the list causes the growing or shrinking the backing array.
For example, if the backing array's initial capacity is 10, such that the array would grow upon the insertion of the 11th element (capacity would grow to 15), a natural implementation would be to shrink the backing array once the list size dropped below 11. If you had a list whose length kept changing between 10 and 11, you'd be constantly changing the backing array. Not only would that add a runtime overhead, but you could start putting lots of pressure on the garbage collector if every operation resulted in either 10 or 15 objects becoming garbage.
Upvotes: 0
Reputation: 415
The comments already cover most of what you are asking. Here some thoughts on your questions:
When creating a structure like the ArrayList
in Java, the developers make certain decisions regarding runtime / performance. They obviously decided to exclude shrinking from the “normal” operations to avoid the additional runtime, which is needed.
The question is why you would want to shrink automatically. The ArrayList
does not grow that much (the factor is about 1.5; newCapacity = oldCapacity + (oldCapacity >> 1)
, to be exact). Maybe you also insert in the middle and not just append at the end. Then a LinkedList
(which is not based on an array -> no shrinking needed) might be better. It really depends on your use case. If you think you really need everything an ArrayList
does, but it has to shrink when removing elements (I doubt you really need this), just extend ArrayList
and override the methods. But be careful! If you shrink at every removal, you are back at O(n)
.
The C# List
and the C++ vector
behave the same concerning shrinking a list at removal of elements. But the factors of automatic growing vary. Even some Java-implementations use different factors.
Upvotes: 4