Sorted Lists
Sorted Lists
In the List interface, the user is given methods which allow data to be entered in any desired order. A new data item being added can be added at the beginning or end of the list, or somewhere in the middle. In many cases, however, the data itself has its own natural ordering (e.g. ordering by magnitude for numbers, lexicographic ordering for strings, etc.). In those cases, we may want to design a class that represents a sorted list; that is, a list whose order is always maintained based on the natural ordering of the data. We could use such a class to store a list of names in alphabetical order or a list of numbers in increasing order.Would such a collection be useful?
To begin the design, answer the following questions:
- What properties would a Sorted List have?
- What (if anything) would be different about a Sorted List in comparison with a List?
- What (if any) requirements might be imposed on the objects in a Sorted List?
- We need a way of comparing objects
- Only one version of add is permitted: add in order
- An iterator for Sorted List should return its objects in increasing order
the Comparable interface
For comparing objects, Java defines a Comparable interface, with a single methodint compareTo(Object obj);
It returns 0 if this == obj, an integer value < 0 if this < obj, and an integer value > 0 if this > obj.
Classes in the Java API with a natural ordering, such as Integer, String, etc., implement Comparable. This makes it possible to use objects from any of those classes in a Sorted List. It's a good idea to do the same for classes you write yourself.
example Define an Employee class, ordered by name.
class Employee implements Comparable {
String name;
String ssn;
.
.
.
int compareTo(Object obj) {
if(! (obj instanceof Employee))
throw new IllegalArgumentException();
Employee employee = (Employee) obj;
return name.compareTo(employee.name);
}
}
the SortedList interface
Define the SortedList interfaceinterface SortedList {
boolean add(Object obj);
Iterator iterator();
void clear();
boolean contains(Object obj);
int indexOf(Object obj);
Object get(int i);
boolean isEmpty();
Object remove(int i);
boolean remove(Object obj);
int size();
String toString();
}
Note the differences from List:
No add(int i, Object obj) method
No set(int i, Object obj) method
Question: Which of these methods can be identical to the same methods in List and which cannot?
Implementation
Like List, a SortedList can be implemented with an array, a head-tail linked list, a circular list, a doubly-linked list, or a recursive linked list. We'll consider the add and indexOf methods of these implementations, beginning with SortedRecursiveList.We'll assume that a SortedRecursiveList has a first and a rest, and that the methods getFirst, getRest, setFirst, setRest, prepend, and removeFirst have been defined. Then we can write add and indexOf as follows:
boolean add(Object obj){
if(!(obj instanceof Comparable))
throw new IllegalArgumentException();
if(isEmpty() || ((Comparable)obj).compareTo(first) < 0)
prepend(obj);
else
rest.add(obj);
return true;
}
int indexOf(Object obj){
if(!(obj instanceof Comparable))
throw new IllegalArgumentException();
if(isEmpty() || ((Comparable)obj).compareTo(first) < 0)
return -1;
else if(((Comparable)obj).compareTo(first) == 0)
return 0;
else {
int i = rest.indexOf(obj);
if(i == -1)
return -1;
else
return i+1;
}
}
Now consider an array implementation. Assume that a SortedArrayList has an array of Objects called array and an integer variable called nitems.
boolean add(Object obj){
if(!(obj instanceof Comparable))
throw new IllegalArgumentException();
int i = nitems;
while( i > 0 && ((Comparable)obj).compareTo(array[i-1]){
array[i] = array[i-1];
i = i - 1;
}
array[i] = obj;
++nitems;
return true;
}
int indexOf(Object obj){
int left = 0;
int right = nitems -1;
int found = 0;
while(!found && left<=right){
int mid = (left+right)/2;
if(obj.equals(array[mid]))
found = true;
else if (((Comparable)obj).compareTo(array[mid]) < 0)
right = mid -1;
else
left = mid + 1;
}
if(found)
return mid;
else
return -1;
}
This version of the indexOf method is called a Binary Search.
Comparators
Question: What if we want to add objects to a SortedList which do not implement Comparable?
Question: What if we want to put the same objects into two SortedLists, with two different orderings?
These questions can be answered by the use of a Comparator. Comparator is a Java interface which contains methods which are used to compare objects. The interface defines the compare method:
int compare(Object o1, Object o2);compare returns 0 if o1 equals o2, an integer < 0 if o1 < o2, and an integer > 0 if o1 > o2.
A Comparator can be used in an implementation of SortedList, say SortedArrayList, as follows:
- Provide two constructors for SortedArrayList, one which has a Comparator as an argument, one which does not.
- If no Comparator is supplied when the SortedArrayList is created, then it is implied that the objects in the list must implement Comparable, and that the compareTo method will be used to compare them.
- If a Comparator is supplied when the SortedArrayList is created, then it is used in comparing elements.
- The add method uses a Comparator if one is provided, and Comparable.compareTo if it is not.
example Write a Comparator for the Employee class which orders employees by their social security numbers.