Sorting is one of the most common complex operations used.
Database systems make use of sorting as a common method
for data presentation to the user interface.
Create the NetBeans project
SortDemo
which with a Main class into which you can install and run these
test programs. The only other thing you'll need is
import java.util.*;
Sorting in Java
Java provides two built-in ways to do sorting:
using the Arrays.sort function on an array.
using the Collections.sort function on a List.
The descriptions of these algorithms and their usage
can be seen in the
Java Data Structures (java.util)
document in the
Arrays
and Collections sections, respectively.
For an array, A, of any primitive types or any
Object type, these are supported:
The Arrays.sort function also gives
the ability to sort a range between two indices.
The "toIndex" argument name is misleading since the sort
range is really between
fromIndex and toIndex 1, inclusive.
Thus these two calls are equivalent:
Arrays.sort(A); is the same as Arrays.sort(A, 0, A.length);
For a list, L, of Comparable elements, this is defined:
Collections.sort(L);
When no Comparator object is passed to a sort algorithm,
sorting is done using the "natural order" of supposedly
Comparable elements as defined by the compareTo function.
The Collections.sort does a type-check that the elements
are Comparable, but
Arrays.sort can only do a run-time check.
All other sorting is done using
a Comparator object, cmp,
passed to the sort function.
Here are the relevant calls:
This first example shows the sorting of an array or list
of Integers
using the natural order:
public static void mainBasic(String[] args) {
Integer[] A = new Integer[20], B = new Integer[20];
Random r = new Random();
for (int i = 0; i < A.length; ++i) {
A[i] = B[i] = new Integer(r.nextInt(40));
}
List<Integer> L = new ArrayList<Integer>(Arrays.asList(A));
System.out.println("A: " + Arrays.toString(A));
Arrays.sort(A);
System.out.println("A sorted: " + Arrays.toString(A));
System.out.println();
System.out.println("B: " + Arrays.toString(B));
Arrays.sort(B,3,7);
System.out.println("B sorted (3,7): " + Arrays.toString(B));
System.out.println();
System.out.println("L: " + L);
Collections.sort(L);
System.out.println("L sorted: " + L);
}
Using a comparator
This second example shows the sorting of an array or list
of Integers using a comparator.
The comparator makes the Integer comparsion like String
comparison.
public static void mainComparator(String[] args) {
Integer[] A = new Integer[20];
Random r = new Random();
for (int i = 0; i < A.length; ++i) {
A[i] = new Integer(r.nextInt(20));
}
Comparator<Integer> cmp = new Comparator<Integer>() {
@Override
public int compare(Integer lhs, Integer rhs) {
return lhs.toString().compareTo(rhs.toString());
}
};
List<Integer> L = new ArrayList<Integer>(Arrays.asList(A));
System.out.println("A: " + Arrays.toString(A));
Arrays.sort(A, cmp);
System.out.println("A: " + Arrays.toString(A));
System.out.println();
System.out.println("L: " + L);
Collections.sort(L, cmp);
System.out.println("L: " + L);
}
User-defined classes/Stability
This third example illustrates how sorting can be done on any
user-defined class whatsoever by defining a suitable comparator
for the class. The class we define
called Email has data values consisting of a
String from and an Date time.
This program illustrates sorting in two ways, based on these
two fields.
public static class Email {
String from;
Date time;
Email( String from, Date time ) { this.from = from; this.time = time; }
@Override
public String toString() { return from + " : " + time; }
}
public static void mainStable(String[] args) {
Email E[] = new Email[] {
new Email( "bob", new GregorianCalendar(2008, 10, 19).getTime() ),
new Email( "john", new GregorianCalendar(2008, 10, 15).getTime() ),
new Email( "steve", new GregorianCalendar(2008, 10, 14).getTime() ),
new Email( "john", new GregorianCalendar(2008, 10, 18).getTime() ),
new Email( "bob", new GregorianCalendar(2008, 10, 16).getTime() ),
new Email( "bob", new GregorianCalendar(2008, 10, 12).getTime() ),
new Email( "steve", new GregorianCalendar(2008, 10, 17).getTime() ),
new Email( "john", new GregorianCalendar(2008, 10, 13).getTime() )
};
Comparator<Email> cmp_from = new Comparator<Email>() {
@Override
public int compare(Email lhs, Email rhs) {
return lhs.from.compareTo(rhs.from);
}
};
Comparator<Email> cmp_time = new Comparator<Email>() {
@Override
public int compare(Email lhs, Email rhs) {
return lhs.time.compareTo(rhs.time);
}
};
System.out.println( "----------------- before" );
for (Email e: E) { System.out.println(e); }
Arrays.sort(E, cmp_time); // sort by time
System.out.println( "----------------- sorted by time" );
for (Email e: E) { System.out.println(e); }
Arrays.sort(E, cmp_from); // sort by from
System.out.println( "----------------- sorted by from" );
for (Email e: E) { System.out.println(e); }
}
The output of this program lookes like this:
----------------- before
bob : Wed Nov 19 00:00:00 GMT-05:00 2008
john : Sat Nov 15 00:00:00 GMT-05:00 2008
steve : Fri Nov 14 00:00:00 GMT-05:00 2008
john : Tue Nov 18 00:00:00 GMT-05:00 2008
bob : Sun Nov 16 00:00:00 GMT-05:00 2008
bob : Wed Nov 12 00:00:00 GMT-05:00 2008
steve : Mon Nov 17 00:00:00 GMT-05:00 2008
john : Thu Nov 13 00:00:00 GMT-05:00 2008
----------------- sorted by time
bob : Wed Nov 12 00:00:00 GMT-05:00 2008
john : Thu Nov 13 00:00:00 GMT-05:00 2008
steve : Fri Nov 14 00:00:00 GMT-05:00 2008
john : Sat Nov 15 00:00:00 GMT-05:00 2008
bob : Sun Nov 16 00:00:00 GMT-05:00 2008
steve : Mon Nov 17 00:00:00 GMT-05:00 2008
john : Tue Nov 18 00:00:00 GMT-05:00 2008
bob : Wed Nov 19 00:00:00 GMT-05:00 2008
----------------- sort by from
bob : Wed Nov 12 00:00:00 GMT-05:00 2008
bob : Sun Nov 16 00:00:00 GMT-05:00 2008
bob : Wed Nov 19 00:00:00 GMT-05:00 2008
john : Thu Nov 13 00:00:00 GMT-05:00 2008
john : Sat Nov 15 00:00:00 GMT-05:00 2008
john : Tue Nov 18 00:00:00 GMT-05:00 2008
steve : Fri Nov 14 00:00:00 GMT-05:00 2008
steve : Mon Nov 17 00:00:00 GMT-05:00 2008
Stable sort
In the above example, the first sort orders the entries by time,
the second sort orders by name.
The fact that the entries which have the
same name are still ordered by time means that the sorting algorithm
used by Java is stable.
A stable sorting algorithm is one in which equal element retain their
same relative ordering. In our case, all the "bob" elements which
were ordered by time are equal with respect to sorting by
the from field, and
they are still ordered by time afterwards.
This stability feature is implicitly used in virtually every User Interface
program which allows the user to list elements according to different
characteristics.