Lecture 14

Selection Sort

Sorting algorithms take a sequence of values and arrange them in sorted order: usually lowest to highest (ascending order), although highest to lowest order (descending order) is sometimes used.

In Java, the simplest way to represent a sequence of values is to use an array.  Therefore, sorting in Java is generally accomplished by re-arranging the elements of an array so they are in sorted order.

Selection sort is a simple sorting algorithm.  Here is the pseudo-code for selection sort:

for each index (curIndex) in the array from 0 to end of the array {
  
  find the index (minIndex) of the minimum value between curIndex and end of array
  
  swap elements at curIndex and minIndex

}

The outer loop proceeds through each position in the array from beginning to end.  Each iteration of the outer loop find the next-smallest element and moves it into the correct location in the array.  Thus, when the outer loop terminates each element of the array will contain the correct element in order for the entire array to be in ascending order.

The steps listed in green are subproblems that we can solve in separate methods, as discussed in Lecture 14.  The method to find the minimum element between curIndex and the end of the array will need to take both curIndex and a reference to the array as input parameters, and will return the index of the minimum value as a return value.  The method to swap two elements in the array will need to take a reference to the array, curIndex, and minIndex as input parameters.  This method does not need to return a value because it works by modifying the input array.

Within the selection sort method, we note that we need variables for curIndex and minIndex.  The method can take the array to be sorted as an input parameter.  Because the method works by modifying the input array, it doesn't need to explicitly return an input value.

Here is the Java code for the selection sort, which is defined to sort an array of double values:

public static void selectionSort(double[] array) {
  int minIndex;
  int curIndex;

  // for each index (curIndex) in the array from 0 to end of the array
  for (curIndex = 0; curIndex < array.length; curIndex++) {

    // find the index (minIndex) of the minimum value between curIndex and end of array
    minIndex = findMinIndex(array, curIndex);

    // swap elements at curIndex and minIndex
    swapValues(array, curIndex, minIndex);
  }
}

findMinIndex

The findMinIndex method is an example of a search algorithm: it needs to find a value with a particular property (being the minimum) among a collection of values.  In this case, we know that we can't prove that any particular element is the minimum unless we examine each element in the collection.  A common pattern for this kind of problem is to start out by assuming that the first value in the collection is the one we are looking for, and then considering each remaining element in the collection.  If we encounter a value that is a better candidate than our current candidate, then we change our assumption to reflect the new information.

Here is the pseudo-code for findMinIndex:

begin by assuming the start element is the minimum value

for each remaining index (curIndex) in range start+1 to end of array {

  see if the element at curIndex is less than current minimum value
  if so, current value is the new minimum value

}

The algorithm uses two items of data:

  1. The index of the minimum element (minIndex)
  2. The index of the current element (curIndex)

These become local variables in the method.

Translation into Java:

private static int findMinIndex(double[] array, int startIndex) {
  int curIndex;
  int minIndex;

  // begin by assuming the start element is the minimum value
  minIndex = startIndex;

  // for each remaining index (curIndex) in range start+1 to end of array
  for (curIndex = startIndex + 1; curIndex < array.length; curIndex++) {

    // see if the element at curIndex is less than current minimum value
    if (array[curIndex] < array[minIndex]) {
      // if so, current value is the new minimum value
      minIndex = curIndex;
    }
  }

  return minIndex;
}

swapValues

The swapValues method exchanges the values of two array elements whose indices are given as input parameters.  A temporary variable is required to perform the exchange:

private static void swapValues(double[] array, int firstIndex, int secondIndex) {
  double temp;

  temp = array[firstIndex];
  array[firstIndex] = array[secondIndex];
  array[secondIndex] = temp;
}

You should convince yourself that this method does indeed perform the task of swapping two array elements, and that it would not have the indended effect without the use of the temporary variable.

Testing

Now that we've completed the selectionSort method and the other implementation methods it relies on, we can test it to make sure it performs correctly on some test data.  Since we are working with arrays of double values, we will need a method to print the contents of an array of double:

public static void printVals(double[] array) {
  for (int i = 0; i < array.length; i++) {
    System.out.print(array[i] + " ");
  }
  System.out.println();
}

With the printVals method in place, we can write a test method:

public static void testSelectionSort() {
  double[] testArray = new double[5];
  testArray[0] = 4.0;
  testArray[1] = 7.0;
  testArray[2] = 1.0;
  testArray[3] = 3.0;
  testArray[4] = 6.0;

  System.out.println("Before sorting");
  printVals(testArray);

  selectionSort(testArray);
  System.out.println("After sorting");
  printVals(testArray);
}

Here is the output of running the test method in the DrJava interactions window:

Welcome to DrJava.
> Sort.testSelectionSort()
Before sorting
4.0 7.0 1.0 3.0 6.0 
After sorting
1.0 3.0 4.0 6.0 7.0 

Multidimensional Arrays

So far we have seen arrays that are sequences of elements, where each element is identified by a single index value.  A multidimensional array is an array where each element is identified by mutliple index values.  For example, in a two-dimensional array, each element is identified by 2 index values, and you can think of it as being like a grid.  A three-dimensional array would be like a cube, and so on.

In the following example, let's say that we're writing a TicTacToe game and we will use a two-dimensional array of integers to represent the game board.

Declaring an array variable:

int[][] gameBoard;

Remember that because arrays are reference types, declaring an array variable does not actually create an array object.  Creating the object must be done using a new expression:

gameBoard = new int[3][3];

Accessing an element---to retrieve the current value of the element, or to assign a new value to the element---is done by providing each index value of the desired element.

gameBoard[0][0] = 1;
System.out.println("value at row 1, column 2: " + gameBoard[1][2]);

Rows and Columns

In a two-dimensional array, one index corresponds to rows of the grid and one index corresponds to columns of the grid.  If the first dimension of the array is rows, then we are using a row-major interpretation.  If the first dimension is columns, then we are using a column-major interpretation.  Neither interpretation is correct or incorrect: instead, it is up to you to decide which you prefer.  The most common interpretation is the row-major interpretation.

As an example, say that we declare and create a two-dimensional array as follows:

int[][] a = new int[2][5];

The following diagram illustrates the difference between the row-major and column-major interpretations: