views:

1272

answers:

5

I have read that LinkedHashMap has faster iteration speed than HashMap because its elements are doubly linked to each other. Additionally, because of this, LinkedHashMap is slower when inserting or deleting elements. Presumably because these links also need to be updated.

Although I can see an analogy to LinkedList vs ArrayList, in that the elements of LinkedList are also doubly-linked, I read that it iterates slower than ArrayList, and has faster insertion and deletion times.

Why is this? Perhaps I am making a mistake somewhere?

Cheers!

+6  A: 

Doug Lea (author of TreeMap and java.util.concurrent) always slapped my (and my classmates') wrists whenever we used a LinkedList. To paraphrase him "there really isn't an good use case for using a LinkedList."

The advantage of an ArrayList is that is backed by an Array, thus whenever possible you have the speed of random access. The case against "inserting at the beginning of the list is faster with LinkedList" might be true, but System.arraycopy() is really fast, and that's what ArrayList uses.

http://www.docjar.com/html/api/java/util/ArrayList.java.html at line 460.

Jeremy
OK, this is clear now about the lists. What about the maps?
Markos Fragkakis
one reason for using a linked list is if you have a tree-like data structure where a given list node can be contained as a node in many other lists. Using an array backed list in this model requires a huge amount of copying and memory overhead. This is, of course, the exception that proves the rule.
Kevin Day
@Day: (same first name here)...Actually, except for in very rare cases, ArrayList will perform faster and uses much less memory than LinkedList, including most insert operations (insert on LinkedList requires a sequential read through the list to find the node). Java does not expose the LinkList node pointers so there is no good way to create the tree. It still operates like a List. On the other hand, using a linked list data structure (not the Java type) does provide more efficient tree structure.
Kevin Brock
@Day: http://www.javaspecialists.eu/archive/Issue027.html contains a good analysis of these classes and a very good replacement `CircularArrayList` (When I last looked at that, there were some small bugs in the class so YMMV, but it was easy to correct and I've made good use of it).
Kevin Brock
From what I remember, ArrayList if you run out of the allocated space will have to create a completely new backing array with more space allocated to it and copy all the old values over. Which can be fairly expensive.
John
@John: Don't remember when DL said System.arraycopy was really fast?
Jeremy
I wasn't saying he did, I was just saying ArrayList has a pretty bad downfall if you exceed the size of its backing array.
John
Doug Lea was right regarding java.util.LinkedList, but only because you can't reference the list nodes. Otherwise, this becomes a _tremendously_ useful data structure. Several structures of java.util are dumbed down from textbook version to make them more accessible to Really Big Audiences (TM).
Dimitris Andreou
+2  A: 

Some details:

The iterator order for LinkedHashMap is the same as insertion order into the map. So the LinkedList portion only has to "insert" at the end (which is O(1) for a linked list that keeps track of the tail), and the Map portion only does a map insert which is O(1). A general linked-list insert is O(N) and an ArrayList insert has to array-copy the contents over 1 slot before an insert can happen.

z5h
LinkedHashMap can also be constructed to use last accessed ordering (see http://java.sun.com/javase/6/docs/api/java/util/LinkedHashMap.html#LinkedHashMap%28int,%20float,%20boolean%29).
Kevin Brock
@Kevin: Good to know! Thanks.
z5h
+4  A: 

Linked lists iteration run-times (accessing each element) are 'theoretically' the same as an array list. Both require O(n) (Big-O Notation) runtime. However, because memory allocation for arrays is over a continuous block of memory (linked lists elements are allocated individually and may be anywhere in memory), caching comes into effect.

Kevin Sylvestre
A: 

To iterate a linked list, one has to follow each and every reference (link) in each element. These references may point almost anywhere, there is no guarantee that the next element follows the current one in memory, which is bad for caching. Because each reference has to be retrieved, it is slower. Arrays are continuous in memory and the next element is just the memory location of the current element incremented with the size of the element.

For a doubly linked list, insertion anywhere in the array is very fast because only references of the preceding and following element have to be changed. An array, on the other hand, is slower because insertion at any point will cause the entire array to be copied to make space for the new element. Even appending an element will also cause the entire array to be copied when there is not enough continuous memory allocated for the array plus the newly added element.

You'll especially notice the insertion differences when dealing with big datasets. No matter how fast arraycopy() may be, a doubly linked list is always faster for insertion. Because HashMaps are rarely iterated and rely on insertion and order, a doubly linked list might give it a performance boost.

Virtlink
Yes, but Java's LinkedList the only way to add at certain points efficiently is to use it's ListIterator. Using the normal add(n, o) method requires iteration through the list each time it is called. This gets tricky when you hide the implementation and use just the List interface and one of the reasons Java has the `RandomAccess` marker interface.
Kevin Brock
+3  A: 

The reason that LinkedHashMap iteration is faster than HashMap iteration is that HashMap iteration has to iterate over all of the buckets, even the empty ones. The the fact that LinkedHashMap has a list pointing to the data means that it can skip the empty buckets. The list in the LinkedHashMap is a linked list because removal times remain constant (rather than O(n) if it was some arrray-backed list).

ILMTitan
+1 for noting the skipped empty buckets. Also, a LinkedHashMap provides a predictable ordering when iterating through the Map (either insertion or last accessed order); a HashMap iterator order is not predictable.
Kevin Brock