CS210 Tuesday, Feb. 28
pa2 extension: submit by noon tomorrow for full credit. Second collection Saturday noon for 5 points off. Deadline.
Sorting and
Searching
Arrays—Weiss Sec. 6.4
If you have a Collection, then it’s easy to put its contents into an array, and then use Arrays.sort() to sort it. See the Collection interface again on pg. 92, and its toArray() method. Thus we know that any Collection can be called upon to deliver an array holding its contents. The element objects are not copied, just their refs. The type of the array is array of Object, very generic.
The Arrays class provides sort functions partially described on pg. 218, 220:
void
sort(Object [] arr); // for use in the case
that the element class
implements Comparable and that compare is what we want
void
sort(Object [] arr,
Comparator cmp); // for use in
other cases. Here
we say how to compare
elements via the Comparator object
But in the actual Arrays class, there are many more versions, to cover the various arrays of primitive types, for example:
void sort(int [] arr);
Example with int array:
int [] a = {1,
4, -1, 10}; // This
is a sequence of ints
in memory
Arrays.sort(a); // this rewrites
the array a to have contents
{-1, 1, 4, 10}.
Similarly we can sort any kind of array of primitive by calling Arrays.sort() directly.
Another important case is array of String. Then we can use the first version above since an array of String IS-A Array of Object.:
String arr1[] = {"hi", "there", "bye"};
Arrays.sort(arr1);
After this, arr1[0] = "bye", arr1[1] = "hi", and arr1[2] = "there".
If you want to sort strings so as to ignore the case of letters, as is done in a phone book for names, you would need to use a Comparator object with sort.
To sort an array of ItemInfo by name, we would need a Comparator.Binary
Search in the
Arrays class
Binary Search, like sort, has various forms for various types of arrays:
public
static int binarySearch(Object
[] arr, Object x);
// assuming elements implement Comparable
public static int binarySearch(int [] arr, int x); // and so on…
The int return value gives the position of x in the array, if it’s non-negative. If it’s negative, its negative value tells where x fits in the array, i.e. x falls between a[p-1] and a[p] for some p. That p determines the negative value returned by binarySearch by the rule: value = - (p+1). For example, if binarySearch returns -3, it means that x falls between a[1] and a[2], since -3 = - (2+1). If it returns -2, x falls between a[0] and a{1}. If it returns -1, x falls below a[0], the lowest possible category.
What’s this funny feature good for? Suppose we have a sorted array and we want to add one more number and maintain the sort. binarySearch will tell us exactly where to put the new value. Of course we would have to shift down all the array elements to the right of that spot to make room.
For the above int array a = {-1, 1, 4, 10}, binarySeach(a, 4) returns 2, an exact match, since a[2] = 4. binarySearch(a, 10) returns 3. binaraySearch(9) returns -4, saying that 9 is between a[2] and a[3].
Comparators.
We have seen that many sorts and searches can be done via "natural order" expressed by Comparable. When we need to set up some other ordering, we need to use a Comparator, an object that knows how to do a particular kind of comparison for a particular type of element.
For example, Comparator<String> caselessComparator
public class CaselessStringComparator implements Comparator<String> {
int compare(String lhs, String rhs)
{
return(lhs.toLowerCase().compareTo(rhs.toLowerCase()));
}
}
Actually we can get this comparator from String:
Then you can use
void sort(Object [] arr, Comparator cmp);
sort(arr1, new CaselessStringComparator());
sort(arr1, String.CASE_INSENSITIVE_ORDER);
Comparators can be used in binarySearch--
public static <T> int binarySearch(T[] arr, T x, Comparator<? super T> cmp);
int spot = binarySearch(arr1, "hi", String.CASE_INSENSITIVE_ORDER);
(of course this assumes we sorted it without case)
Also in TreeSet (and TreeMap) creation:Stack idea: think of the stack of plates in old diners that were held in a spring-loaded canister so that only the top plate showed. When you took off one plate another popped up into place, ready to be taken. You could put another in, and the pile would sink a little so that the new one was now on at the normal top.
Similarly, a "pure" Stack data structure holds elements, but only gives access to the last one in, the element at “top of stack.” When we push another element in, it becomes the new top element, and the rest are hidden inside the stack. We can pop the stack, removing one element, making the next element the top element.
Thus the main operations of classical academic Stack are push(Object), Object top(), and pop(), as shown on pg. 226. There are two versions of pop extant in the CS world, one which returns the top object, and one that doesn’t. In both cases pop removes (pops off) the old top element.
Clearly we can use an interface to describe a Stack, and Weiss does this on pg. 226, using the version of pop() that returns void. This is his own interface, not a Java standard. However it captures a classic stack setup, which we can call a pure stack, as opposed to some practical setup such as we might find in the JDK.
Clearly we can make a Stack from a List, and you’ll do this in pa3. A stack is a specialized list. Why bother with it then?
Because it provides an important mental model for doing certain calculations, as we will see. When you know a stack is in use, you know what operations are going to be used, and that most of the elements are just going to hide away out of sight for a while until they come back into play when they get to the top.
ReverseLines Example done with a Stack
As a first example, consider a ReverseLines program that read lines from a file and output them in reverse order. We can implement this with a stack of String.
Picture of a stack of three lines after 3 pushes, only last line shows on top.
Top gives last line, output it, pop the stack
Now the next-to-last (middle of the three) line is visible at the top of stack.
Top gives middle line, output it, pop the stack
Now the first line is visible at the top of stack.
Top gives first line, output it, pop the stack.
Now the stack is empty, and we're done.