8

In JDK 1.8, the first statement of the java.util.List#sort(Comparator) method is the following:

Object[] a = this.toArray();

It's expensive to copy the list into an array, sort it, and reset every node of the list to the sorted value from the array.

It seems like it's possible not to copy values to a temporary array when sorting an ArrayList. Am I right? If not, what guided the creators of the method?

2
  • 2
    There are many list implementations, including linked lists, where sorting the list itself may be more expensive. Commented May 17, 2015 at 18:27
  • 1
    "It seems like it's possible not to copy values to array in the case of ArrayList." - and that's exactly how it's done. Commented May 17, 2015 at 18:36

3 Answers 3

10

The sort in the java.util.List interface is just the default implementation of the list sort.

ArrayList overrides this default with a sort method which does sort its internal array directly.

Sign up to request clarification or add additional context in comments.

Comments

8

For ArrayList, or other random access Lists, you may be correct.

However, Collections.sort supports any List implementation. For a LinkedList, for example, it would have been very expansive to swap elements during the sort (since finding the i'th element takes linear time).

Converting the List to an array, and setting the elements of the original List after the array is sorted adds a linear time component to the algorithm, which doesn't change the asymptotic running time of (O(nlog(n))).

2 Comments

It seems like simple code like: if(this instanceof ArrayList) { // only sort } else { // do stuff as usual } will improve the method. Am i right?
@the_kaba This is not necessary: As greg pointed out, the implementations like ArrayList will have this default method overridden, so that they can perform the sort without creating an array first.
7

In OpenJDK 1.8, java.util.ArrayList#sort(Comparator) does not copy its internal array; it sorts in place, as you suggest it should.

The implementation of java.util.List#sort() you're criticizing has the following accompanying documentation:

The default implementation obtains an array containing all elements in this list, sorts the array, and iterates over this list resetting each element from the corresponding position in the array. (This avoids the n² log(n) performance that would result from attempting to sort a linked list in place.)

That is, copying the array and moving around with random access is more efficient than the overhead of striding around linearly in a linked list. The common implementation attempts to trade copying overhead for element access overhead. For cases like ArrayList where the copying isn't necessary to get the same random access to elements, the library omits the copy by overriding the method.

An interesting comparison: Look at the C++ Standard Library's std::sort() and std::list::sort() functions:

  • std::sort() Requires parameters that delimit a range with random access.
  • std::list::sort() Assumes only linear access by traversing linked list nodes.

The generic std::sort() algorithm is more efficient, but the library precludes calling it on a std::list (which is a linked list, akin to Java's java.util.LinkedList). The library provides a less efficient means to sort a std::list for convenience. Unlike the Java library, the C++ library does not copy a std::list() to an array in order to use the random access std::sort() algorithm.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.