Module 3: Supplemental Material


Selection

Let's examine the code we wrote for finding the smallest element in an array:

    static int findSmallest (int[] A)
    {
        // Start by assuming first is smallest.
	int smallest = A[0];

        // Check against A[1], A[2] ... etc.
	for (int i=1; i < A.length; i++) {
	    if (A[i] < smallest) {
		smallest = A[i];
	    }
	}

	return smallest;
    }

Let's look at two variations:

    static int findSmallest2 (int[] A)
    {
        // Start with the largest possible int value.
	int smallest = Integer.MAX_VALUE;

        // Check against A[0], A[1], ...
	for (int i=0; i < A.length; i++) {
	    if (A[i] < smallest) {
		smallest = A[i];
	    }
	}

	return smallest;
    }



    static int findSmallest3 (int[] A)
    {
        // Robustness checks: check that array can be referenced.
        if ( (A == null) || (A.length == 0) ) {
            // ... need to take action ...
            // Return -1? System.exit?
        }
        

        // Start by assuming first is smallest.
	int smallest = A[0];

        // Check against A[1], A[2] ... etc.
	for (int i=1; i < A.length; i++) {
	    if (A[i] < smallest) {
		smallest = A[i];
	    }
	}

	return smallest;
    }
Note:

Exercise 1: Answer these questions:


Selection Sort

Recall the code for Selection-Sort (for arrays of int's):

    static void selectionSort (int[] A)
    {
        // We don't need to find the n-th smallest, so stop at n-1.
	for (int i=0; i < A.length-1; i++) {

	    // Find i-th smallest and swap.
	    int smallest = A[i];
	    int pos = i;

            // Look from i+1 and up.
	    for (int j=i+1; j < A.length; j++) {
		if (A[j] < smallest) {
		    smallest = A[j];
		    pos = j;
		}
	    }

	    // Swap into position i.
	    int temp = A[i];
	    A[i] = A[pos];
	    A[pos] = temp;

	}

Exercise 3: What would happen if the comparison

		if (A[j] < smallest) {
  
were changed to
		if (A[j] <= smallest) {
  
in the if-statement? Also, put the code for swapping in a separate swap method.

We've sorted 1D arrays so far. Can one sort a 2D array?

For fun, let's sort an image:

Here's the program:
import java.awt.*;
import java.awt.image.*;

public class SortPixels {

    public static void main (String[] argv)
    {
	ImageTool imTool = new ImageTool ();
	Image image = imTool.readImageFile ("FamousPerson.jpg");
	imTool.showImage (image, "Original");
	Image sortedImage = sort (image);
	imTool.showImage (sortedImage, "Sorted pixels");
    }
    
    static Image sort (Image image)
    {
	ImageTool imTool = new ImageTool ();
	int[][][] pixels = imTool.imageToPixels (image);

        // We'll do a selection sort.
	for (int i=0; i < pixels.length; i++) {
	    for (int j=0; j < pixels[i].length; j++) {

                // Find (i,j)-th minimum, using only the R value.
                int min = pixels[i][j][1];
                int pos1 = i, pos2 = j;

                // For i-th row, we have to go along row.
                for (int n=j+1; n < pixels[i].length; n++) {
                    if (pixels[i][n][1] < min) {
                        min = pixels[i][n][1];
                        pos1 = i;
                        pos2 = n;
                    }
                }
                
                // Now from row i+1 onwards.
                for (int m=i+1; m < pixels.length; m++) {
                    for (int n=0; n < pixels[m].length; n++) {
                        if (pixels[m][n][1] < min) {
                            min = pixels[m][n][1];
                            pos1 = m;
                            pos2 = n;
                        }
                    }
                }
                
                // Now swap into (i,j) place.
                for (int k=0; k < 4; k++) {
                    int temp = pixels[i][j][k];
                    pixels[i][j][k] = pixels[pos1][pos2][k];
                    pixels[pos1][pos2][k] = temp;
                }
                

	    } //end-for-jj

            // Because it runs slowly, we'll print updates ...
            System.out.println ("Finished row i=" + i);

	} //end-for-i

	return imTool.pixelsToImage (pixels);
    }

}

Exercise 4: Implement and run the above program on this image. See if the sorted result makes sense. Can you identify the person in the image?

If that seemed confusing, let's try something simpler:

Here's the program:
public class RowSort {

    public static void main (String[] argv)
    {
        // Some test data:
        int[][] A = {
            {1, 0, 1},
            {1, 1, 1},
            {1, 0, 0},
            {0, 0, 0}
        };

        // Before:
        print (A);

        rowSort (A);

        // After:
        print (A);
    }


    static void rowSort (int[][] X)
    {
        // Simple Selection Sort. We are sorting only rows.
        for (int row=0; row < X.length; row++) {

            // This is the minimum so far.
            int min = rowSum (X[row]);
            int bestRow = row;

            // Scan remainder to see if there's a better one.
            for (int row2=row+1; row2 < X.length; row2++) {
                int sum = rowSum (X[row2]);
                if (sum < min) {
                    min = sum;
                    bestRow = row2;
                }
            }

            // This is a pointer swap: X[row] is NOT an int. It's a pointer to int[].
            int[] temp = X[row];
            X[row] = X[bestRow];
            X[bestRow] = temp;
        }
    }


    static int rowSum (int[] Y)
    {
        // Sum of elements of a row.
        int sum = 0;
        for (int i=0; i < Y.length; i++) {
            sum += Y[i];
        }
        return sum;
    }
    

    
    static void print (int[][] X)
    {
       // ... straightforward ...
    }

}
Note:

Exercise 5: Does the same idea work for sorting columns? Download ColumnSort.java and implement a column sort: sort the columns by column-sum (the sum of elements in a column).


Sorting objects

Let's return to the example where we sorted objects and make a few modifications:

Here's the (somewhat complicated) program:
// The class we define for "Person" objects:

class Person {

    // Some data:
    String firstName;
    String lastName;
    int birthYear;
    
    // We'll use this to decide what kind of sorting we want.
    public boolean sortByAge = false;


    // This is called a constructor:

    public Person (String firstName, String lastName, int birthYear)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.birthYear = birthYear;
    }


    // To allow for printing via System.out.println:

    public String toString ()
    {
        return "Person: " + firstName + " " + lastName + " (b. " + birthYear + ")";
    }
    


    // A comparison method to allow two Person instances to be compared.

    public boolean lessThan (Person p)
    {
        if (sortByAge) {
            // Compare ages.
            if (birthYear < p.birthYear) {
                return true;
            }
            else {
                return false;
            }
        }
        else {
            // Sort alphabetically by name, starting with lastname.
            if ( lastName.compareTo (p.lastName) < 0 ) {
                return true;
            }
            else if ( lastName.compareTo (p.lastName) > 0 ) {
                return false;
            }
            
            // If last names are equal, try first names.
            if ( firstName.compareTo (p.firstName) < 0 ) {
                return true;
            }
            else if ( firstName.compareTo (p.firstName) > 0 ) {
                return false;
            }

            // If both names are equal, use age.
            if (birthYear < p.birthYear) {
                return true;
            }
            else {
                return false;
            }
        }
    }

} //end-Person




public class ObjectSortExample2 {

    public static void main (String[] argv)
    {
        Person[] someKennedys = new Person [10];

        Person p = new Person ("Patrick", "Kennedy", 1858);

        System.out.println ("First one: " + p);
        someKennedys[0] = p;
        
        // Do the others:
        someKennedys[1] = new Person ("Joseph", "Kennedy", 1888);
        someKennedys[2] = new Person ("Rose", "Fitzgerald", 1890);
        someKennedys[3] = new Person ("Joseph", "Kennedy", 1915);
        someKennedys[4] = new Person ("John", "Kennedy", 1917);
        someKennedys[5] = new Person ("Jacqueline", "Bouvier", 1929);
        someKennedys[6] = new Person ("Robert", "Kennedy", 1925);
        someKennedys[7] = new Person ("Edward", "Kennedy", 1932);
        someKennedys[8] = new Person ("Caroline", "Kennedy", 1957);
        someKennedys[9] = new Person ("Maria", "Shriver", 1955);

        System.out.println ("Unsorted: ");
        print (someKennedys);

        System.out.println ("Sorted: ");
        sort (someKennedys);
        print (someKennedys);
        
        // We want to sort by age, so set that flag in all instances.
        for (int i=0; i < someKennedys.length; i++) {
            someKennedys[i].sortByAge = true;
        }

        System.out.println ("Sorted by age: ");
        sort (someKennedys);
        print (someKennedys);
        
    }



    static void print (Person[] people)
    {
        for (int i=0; i < people.length; i++) {
            // people[i] is a Person instance.
            System.out.println (people[i]);
        }
    }
    


    static void sort (Person[] people)
    {
        // Selection Sort.
	for (int i=0; i < people.length-1; i++) {

	    // Find i-th min and swap.
	    Person min = people[i];
	    int pos = i;

            // Scan the rest.

	    for (int j=i+1; j < people.length; j++) {
		if ( people[j].lessThan (min) ) {
		    min = people[j];
		    pos = j;
		}
	    }

	    // Swap.
	    Person temp = people[i];
	    people[i] = people[pos];
	    people[pos] = temp;
	}
    }
    
}
The are many things to note:
  • We've now added a flag to let us decide whether to sort by age or by name:
        // We'll use this to decide what kind of sorting we want.
        public boolean sortByAge = false;
        

  • Notice how a "constructor" is defined:
        public Person (String firstName, String lastName, int birthYear)
        {
            this.firstName = firstName;
            this.lastName = lastName;
            this.birthYear = birthYear;
        }
        
    • It's like a method (with parameters)
    • It must be public and cannot have a return type declared.
    • A constructor executes only once per instance when the instance is created.
    • There's a lot more to constructors; we've only introduced them here. See the advanced Java material for more details.

  • There's a special method defined called toString():
        public String toString ()
        {
            return "Person: " + firstName + " " + lastName + " (b. " + birthYear + ")";
        }
        
    • Java treats this a little differently.
    • A little later in main, you see the line
              Person p = new Person ("Patrick", "Kennedy", 1858);
              System.out.println ("First one: " + p);
             
    • Whenever an object is given to System.out.println() or invoked where there should be a String, Java automatically calls the object's toString() method.
    • This is useful for debugging, when we want to dump an object's contents to screen.
    • We don't have to write
                System.out.println (p.firstName);
                System.out.println (p.lastName);
                System.out.println (p.birthYear);
             
    • Instead, we write
                System.out.println (p);
             

  • Moving on (in main), we see that a sort-by-name occurs first. Then we set sortByAge=true in each instance, and sort again.

  • We use a simple Selection-Sort.

  • To compare two Person instances, we simply call the lessThan() method we defined for one of them, and pass the other as parameter:
                    // "min" is of type Person.
    		if ( people[j].lessThan (min) ) {
                        // ...
                    }
         

  • We needed a Person variable for the swap:
    	    // Swap.
    	    Person temp = people[i];
    	    people[i] = people[pos];
    	    people[pos] = temp;
         

Now for something more complicated (but more useful):

  • We will make our Person object satisfy the interface called Comparable in the Java library.
    class Person implements Comparable {
    
        // ...
    
    }
        

  • This requires us to implement a method called compareTo():
    class Person implements Comparable {
    
        // ...
    
        public int compareTo (Object d)
        {
            // ...
        }
    }
        

  • Why should we do this?
    • By making our class Person implement the Comparable, we are in effect saying that it can behave like a Comparable object.
    • The only behavior required of a Comparable object is to have the method
          public int compareTo (Object d)
          {
              // ...
          }
          
      implemented correctly.
    • Here, "correctly" means: proper comparison of Person instances.
    • Once this is done, we can take advantage of any sorting algorithm written for Comparable objects.
    • For example, Java's own sorting algorithm in the Arrays class:
            public static void sort (Object[] A)
            

  • The code below uses Java's sorting algorithm.
Here's the program:
import java.util.*;

class Person implements Comparable<Person> {

    // Some data:
    String firstName;
    String lastName;
    int birthYear;
    
    // We'll use this to decide what kind of sorting we want.
    public boolean sortByAge = false;


    // This is called a constructor:

    public Person (String firstName, String lastName, int birthYear)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.birthYear = birthYear;
    }


    // To allow for printing via System.out.println:

    public String toString ()
    {
        return "Person: " + firstName + " " + lastName + " (b. " + birthYear + ")";
    }
    


    // A comparison method to allow two Person instances to be compared.

    public int compareTo (Person d)
    {
        // Check if object passed in is of correct type.
        if (! (d instanceof Person) ) {
            return -1;
        }
        
        // Cast to a Person variable so that we can access fields.
        Person p = (Person) d;

        if (sortByAge) {
            // Compare ages.
            if (birthYear < p.birthYear) {
                return -1;
            }
            else if (birthYear > p.birthYear) {
                return 1;
            }
            else {
                return 0;
            }
            
        }
        else {
            // Sort alphabetically by name, starting with lastname.
            if ( lastName.compareTo (p.lastName) < 0 ) {
                return -1;
            }
            else if ( lastName.compareTo (p.lastName) > 0 ) {
                return 1;
            }
            
            // If last names are equal, try first names.
            if ( firstName.compareTo (p.firstName) < 0 ) {
                return -1;
            }
            else if ( firstName.compareTo (p.firstName) > 0 ) {
                return 1;
            }
            else {
                return 0;
            }
        }
    }

} //end-Person




public class ObjectSortExample4 {

    public static void main (String[] argv)
    {
        Person[] someKennedys = new Person [10];

        Person p = new Person ("Patrick", "Kennedy", 1858);

        System.out.println ("First one: " + p);
        someKennedys[0] = p;
        
        // Do the others:
        someKennedys[1] = new Person ("Joseph", "Kennedy", 1888);
        someKennedys[2] = new Person ("Rose", "Fitzgerald", 1890);
        someKennedys[3] = new Person ("Joseph", "Kennedy", 1915);
        someKennedys[4] = new Person ("John", "Kennedy", 1917);
        someKennedys[5] = new Person ("Jacqueline", "Bouvier", 1929);
        someKennedys[6] = new Person ("Robert", "Kennedy", 1925);
        someKennedys[7] = new Person ("Edward", "Kennedy", 1932);
        someKennedys[8] = new Person ("Caroline", "Kennedy", 1957);
        someKennedys[9] = new Person ("Maria", "Shriver", 1955);

        System.out.println ("Unsorted: ");
        print (someKennedys);

        System.out.println ("Sorted: ");
        // Java's sort method.
        Arrays.sort (someKennedys);
        print (someKennedys);
        
        // We want to sort by age, so set that flag in all instances.
        for (int i=0; i < someKennedys.length; i++) {
            someKennedys[i].sortByAge = true;
        }

        System.out.println ("Sorted by age: ");
        // Java's sort method:
        Arrays.sort (someKennedys);
        print (someKennedys);
        
    }



    static void print (Person[] people)
    {
        // ...
    }
    
}



© 2006-2020, Rahul Simha & James Taylor (revised 2020)