<<

Comparison Comparisons and the Comparable • Something that we do a lot Interface • Can compare all kinds of data with respect to all kinds of comparison relations . . Equality Lecture 14 . Order CS211 – Spring 2006 . Lots of others

Identity vs. Equality Identity vs. Equality for Strings

• For primitive types (e.g., int, long, float, double, boolean) . == and != are equality tests • Quiz: What are the results of the following tests? • For reference types (i.e., objects) . "hello".equals("hello") true . == and != are identity tests . In other words, they test if the references indicate the same address . "hello" == "hello" true in the Heap . "hello" == new String("hello") false • For equality of objects: use the equals( ) method . equals( ) is defined in class Object . Any class you create inherits equals from its parent class, but you can override it (and probably want to)

Notions of equality Order

• A is equal to B if A can be substituted for B anywhere • For numeric primitives • For all other reference . Identical things must be equal: == implies equals (e.g., int, float, long, types double) • Immutable values are equal if they represent same value! . <, >, <=, >= do not work . Use <, >, <=, >= • Not clear you want them . (new (2)).equals(new Integer(2)) to work: suppose we . == is not an abstract operation compare People • For reference types that  Compare by name? • Mutable values can be distinguished by assignment. correspond to primitive  Compare by height? class Foo { int f; Foo(int g) { f = g; } } weight? types  Compare by SSN? Foo x = new Foo(2); . As of Java 5.0, Java does CUID? Foo y = new Foo(2); Autoboxing and Auto- . Java provides Comparable Unboxing of Primitive interface . x.equals(y)? Not really (x.f = 1), but Java fudges equality Types • Or can use a Comparator • Shallow equality: x equals y if all components are == . This means, for example, • Deep equality: x equals y if all components are (deep) equal that an Integer is automatically converted into an appropriate int whenever necessary (and vice versa)

1 Comparable Interface Example

• To compare people by weight:

interface Comparable { class Person implements Comparable { int compareTo(Object x); private int weight; } ... public int compareTo(Object obj) { • (Note: this is Java 1.4.2 – Java 5.0 has generics) return ((Person)obj).weight - weight; • x.compareTo(y) returns a negative, zero, or positive integer based on } whether x is less-than, equal-to, or greater-than y, respectively public boolean equals(Object obj) { • less-than, equal-to, and greater-than are defined for that class by the return obj instanceof Person && implementation of compareTo ((Person)obj).weight == weight; } }

Consistency Generic Code • The Comparable interface allows generic code for If a class has an equals method and also sorting, searching, and other operations that only require implements Comparable, then it is advisable (but comparisons not enforced) that static void mergeSort(Comparable[] a) {...} a.equals(b) static void bubbleSort(Comparable[] a) {...} exactly when • The sort methods do not need to know what they are sorting, a.compareTo(b) == 0 only how to compare elements

Odd behavior can result if this is violated

Generic Code Example Another Example • Finding the max of an array • Lexicographic comparison of Comparable arrays • for int arrays, a < b lexicographically iff either: //return max element of an array . a[i] == b[i] for i < j and a[j] < b[j]; or static Comparable max(Comparable[] a) { . a[i] == b[i] for all i < a.length, and b is longer //throws ArrayIndexOutOfBoundsException Comparable max = a[0]; for (Comparable x : a) { //compare two Comparable arrays lexicographically if (x.compareTo(max) > 0) max = x; static int arrayCompare(Comparable[] a, Comparable[] b) } { return max; for (int i = 0; i < a.length && i < b.length; i++) { } int x = a[i].compareTo(b[i]); if (x != 0) return x; } • What is the max element? Whatever compareTo return b.length - a.length; says it is! }

2 Comparable Interface Update Example • Java 5.0 allows the use of “Generic Types” • In the Java source code, class String looks sort of . Aka parameterized types (other interfaces are also implemented) like this: . Here’s the Java 5.0 Comparable interface public final class String implements Comparable{ interface Comparable { public int compareTo (String s) {...} int compareTo(T x); ...} }

. compareTo is only defined for arguments of type T • Code such as • Attempts to use a different type are caught at compile time “hello”.compareTo(new Integer(3)) generates a compile-time error . This implies that the runtime code can be more efficient

Using Comparable for Sorting Unnatural Sorting

• Sorting of arrays provided by Java Collections Framework: • The ordering given by interface Comparator { import java.util.Arrays; compareTo is considered to int compare (T x, T y); } ... be the natural ordering for a class String[] names; • Can use a Comparator (a class ... • Sometimes you need to sort that implements the based on a different Arrays.sort(names) Comparator interface) ordering Arrays.sort(students, comparator) • This works for arrays of type comparableType[ ] (the base . Example: we may normally type must implement the Comparable interface) sort students by CUID, but we might want to produce a • String, for example, has a • (Class java.util.Arrays also contains sort methods for arrays list alphabetized by name of type primType[ ] for each primitive type) predefined Comparator: String.CASE_INSENSITIVE_ORDER

Efficient Programs Linear Search • Have been talking a lot about how to make writing • Input: programs efficient . Unsorted array A of Comparables . Value v of type Comparable . Interfaces, encapsulation, inheritance, type checking, recursion vs. iteration, … • Output: . True if v is in array A, false otherwise • Haven’t talked much about how to make the programs themselves run efficiently • : examine the elements of A in some order until . How long does it take program to run? you either . Is there an efficient data structure that should be used? . Find v: return true, or . Is there a faster algorithm? . You have unsuccessfully examined all the elements of the array: return false

3 Code for Linear Search Binary Search

// Linear search on possibly unsorted array • Input: public static boolean linearSearch(Comparable[ ] a, Object v) { . Sorted array A[0..n-1] of Comparable for (int i = 0; i < a.length; i++) . Value v of type Comparable if (a[i].compareTo(v) == 0) return true; • Output: return false; . True if v is in array A, false otherwise } • Algorithm: similar to looking up telephone directory . Let m be the middle element of the array . If (m == v) return true . If (m < v) search right half of array . If (m > v) search left half of array 2 1 Linear search: 7 4 6 19 3 7 8 10 32 54 67 98 Search for 6 -2 0 6 8 9 1113 22 34 45 56 78

Search for 94 1 2 3 4

// Lo and hi are the two end points of interval of array public static boolean binarySearch(Comparable[] a, int lo, int hi, Object v) { Comparing int middle = (lo + hi)/2; int c = A[middle].compareTo(v); • If you run binary search and linear search on a

// Base cases computer, you will find that binary search runs if (c == 0) return true; much faster than linear search // Check if array interval has only one element if (lo == hi) return false; • Stating this precisely can be quite subtle

// Array interval has more than one element, so continue searching • One approach: asymptotic complexity of programs if (c > 0) return binarySearch(a, lo, middle -1, v); // Left half else return binarySearch(a, middle+1, hi, v); // Right half . Big-O analysis } • Two steps: . Compute running time of program Invocation: assume array named data contains values . Running time ⇒ asymptotic running time ….. binarySearch(data, 0, data.length -1, v)…..

Running Time of an Algorithm Defining an Algorithm’s Running Time • In general, running time of a program such as 1. Machine on which algorithm (i.e., program) is executed linear search depends on many factors . Random-access Memory (RAM) model of computing • Measure of running time: number of operations executed . Machine on which program is executed . Other models used in CS: Turing machine, Parallel RAM model, • Laptop vs. supercomputer … . Size of input (array A) . Simplified RAM model for now: • Big array vs. small array • Each data comparison is one operation. . Values in array and value we search for • All other operations are free. • Evaluate searching/sorting algorithms by estimating number of • v is first element examined in array vs. v is not in array comparisons they execute • To talk precisely about running times of programs,  It can be shown that, for comparison-based searching and sorting algorithms, the total number of operations executed on RAM model is we must specify all three factors above proportional to number of data comparisons executed

4 Defining Running Time (cont’d) Defining Running Time (cont’d)

2. Dependence on size of input 3. Dependence of running • Consider In of all . Rather than compute a single number, we will time on input values possible inputs of size n compute a from problem size to number of • Find number of comparisons comparisons for each • E.g., f(n) = 32n2 – 2n + 23 where n is problem size possible input in this set . Each program has its own measure of problem size • Compute . For searching/sorting, natural measure is size of array . Average: usually hard to ([3,6], 2) compute on which you are searching/sorting ([-4,5], -9) . Worst-case: easier to ([3,6], 3) ……. compute • We will use worst-case Possible inputs of size 2 complexity for linear/binary search

Computing Running Times

Linear search: 7 4 6 19 3 7 8 10 32 54 67 98

Assume array is of size n. Worst-case number of comparisons: v is not in array. Number of comparisons = n.

Running time of linear search: TL(n) = n

Binary search: sorted array of size n

-2 0 6 8 9 1113 22 34 45 56 78

Worst-case number of comparisons: v is not in array.

TB(n) = log2(n) + 1

5