views:

1456

answers:

6

What is the fastest list implementation (in java) in a scenario where the list will be created one element at a time then at a later point be read one element at a time? The reads will be done with an iterator and then the list will then be destroyed.
I know that the Big O notation for get is O(1) and add is O(1) for an ArrayList, while LinkedList is O(n) for get and O(1) for add. Does the iterator behave with the same Big O notation?

+5  A: 

Iterating through a linked list is O(1) per element.

The Big O runtime for each option is the same. Probably the ArrayList will be faster because of better memory locality, but you'd have to measure it to know for sure. Pick whatever makes the code clearest.

Khoth
+6  A: 

First Thoughts:

  • Refactor your code to not need the list.
  • Simplify the data down to a scalar data type, then use: int[]
  • Or even just use an array of whatever object you have: Object[] - John Gardner
  • Initialize the list to the full size: new ArrayList(123);

Of course, as everyone else is mentioning, do performance testing, prove your new solution is an improvement.

KyleLanser
Or even just use an array of whatever object you have, if you can't simplify it to a scalar type.
John Gardner
This is a bad answer. The performance cost here doesn't come from creating the list, it comes from choosing the wrong implementation based upon how he's using it. Using an array over an ArrayList won't help if he's adding lots of objects because you still need a new array once you reach the max.
Outlaw Programmer
won't help if he's adding lots of objects because you still need a new array once you reach the max --- thats why i suggested initializing to the biggest size its gonna be.
KyleLanser
More importantly, I'm simply listing some things they could try doing that MIGHT help, and if performance testing says they do help, then cool.
KyleLanser
Re: Outlaw. We dont know where the performance cost is coming from, maybe its memory space, maybe there's a bandwidth issue, maybe its just raw CPU cycles (embedded Javelin Stamp stuff).
KyleLanser
+2  A: 

I suggest benchmarking it. It's one thing reading the API, but until you try it for yourself, it'd academic.

Should be fair easy to test, just make sure you do meaningful operations, or hotspot will out-smart you and optimise it all to a NO-OP :)

skaffman
+2  A: 

Note that iterating through an instance of LinkedList can be O(n^2) if done naively. Specifically:

List<Object> list = new LinkedList<Object>();
for (int i = 0; i < list.size(); i++) {
    list.get(i);
}

This is absolutely horrible in terms of efficiency due to the fact that the list must be traversed up to i twice for each iteration. If you do use LinkedList, be sure to use either an Iterator or Java 5's enhanced for-loop:

for (Object o : list) {
    // ...
}

The above code is O(n), since the list is traversed statefully in-place.

To avoid all of the above hassle, just use ArrayList. It's not always the best choice (particularly for space efficiency), but it's usually a safe bet.

Daniel Spiewak
+6  A: 

It depends largely on whether you know the maximum size of each list up front.

If you do, use ArrayList; it will certainly be faster.

Otherwise, you'll probably have to profile. While access to the ArrayList is O(1), creating it is not as simple, because of dynamic resizing.

Another point to consider is that the space-time trade-off is not clear cut. Each Java object has quite a bit of overhead. While an ArrayList may waste some space on surplus slots, each slot is only 4 bytes (or 8 on a 64-bit JVM). Each element of a LinkedList is probably about 50 bytes (perhaps 100 in a 64-bit JVM). So you have to have quite a few wasted slots in an ArrayList before a LinkedList actually wins its presumed space advantage. Locality of reference is also a factor, and ArrayList is preferable there too.

In practice, I almost always use ArrayList.

erickson
+1  A: 

You almost certainly want an ArrayList. Both adding and reading are "amortized constant time" (i.e. O(1)) as specified in the documentation (note that this is true even if the list has to increase it's size - it's designed like that see http://java.sun.com/j2se/1.5.0/docs/api/java/util/ArrayList.html ). If you know roughly the number of objects you will be storing then even the ArrayList size increase is eliminated.

Adding to the end of a linked list is O(1), but the constant multiplier is larger than ArrayList (since you are usually creating a node object every time). Reading is virtually identical to the ArrayList if you are using an iterator.

It's a good rule to always use the simplest structure you can, unless there is a good reason not to. Here there is no such reason.

The exact quote from the documentation for ArrayList is: "The add operation runs in amortized constant time, that is, adding n elements requires O(n) time. All of the other operations run in linear time (roughly speaking). The constant factor is low compared to that for the LinkedList implementation."

DJClayworth
Adding to `LinkedList` (which behaves as doubly-linked and maintains a reference to head and tail) is certainly *not* O(n) unless you are inserting at an arbitrary index. An insert into an `ArrayList` is *not* O(1) if it triggers an increase in capacity; it does use `System.arraycopy`, though.
Hank Gay
Please read the documentation for ArrayList.
DJClayworth
Specifically the documentation says:The add operation runs in amortized constant time, that is, adding n elements requires O(n) time. All of the other operations run in linear time (roughly speaking). The constant factor is low compared to that for the LinkedList implementation.
DJClayworth
The key word there is "amortized". That means they're distributing the cost of that one resize-triggering insert across all the other inserts for purposes of that calculation. Feel free to look at the source and see that it allocates a new, larger array and copies the elements from the old to new.
Hank Gay
Thanks, I read the source a long time ago, and fully understand how ArrayList works, which is why I wrote that.
DJClayworth