# Class 26: Some Sorting Algorithms

Back to Introduction to Sorting. On to More Efficient Sorting Algorithms.

Held Tuesday, March 7, 2000

Overview

Today we continue our discussion of sorting by investigating two other simple sorting algorithms: bubble sort and selection sort. We also visit other issues in the design of sorting algorithms.

Notes

• Are there questions on Assignment 3?
• Are there questions on Project, Phase 3?
• Reminder: I'll be gone from noon Wednesday until Sunday. I'll be at the SIGCSE Symposium on Computer Science Education.

Contents

Summary

• Comparators
• Two basic sorting methods:
• Selection sort
• Bubble sort
• Choosing a sorting method

## Comparators

• We've decided that it's most natural to have our sorting algorithms take a comparator as a parameter.
• In Scheme, you took a comparison function as a parameter.
• In Java, our sort method will now look like:
```public void sortThyself(Comparator compare);
```
• What should the `Comparator` interface look like?
• We may need to compare for equality.
• Hence, it will need an `equals(Object,Object)` method.
• We certainly need to compare for ordering.
• Hence, it will need a `precedes(Object,Object)` method.
• Is that all we need to worry about? No, what happens if the two objects cannot be compared (e.g., if we call precedes with a game board and a student information record)?
• We should throw an exception.
• Putting it all together:
```
/**
* Objects that can compare pairs of objects (for equality and
* ordering).  We assume that if something is neither less than
* or equal to another object, then it is greater than that other
* object.  Typically used to help with sorting.
*
* @author Samuel A. Rebelsky
* @version 1.2 of March 2000
*/
public interface Comparator {
/**
* Determine if the first element should precede the
* second.   Throws an exception if the two elements cannot
* be compared.
*/
public boolean precedes(Object first, Object second)
throws IncomparableException;

/**
* Determine if the first element is equal to the second.   Throws
* an exception if the two elements cannot be compared.
*/
public boolean equals(Object first, Object second)
throws IncomparableException;

} // interface Comparator

```
• Let's consider some comparators for the `StudentInfo` class we were designing.
• `StudentNameComparator`
• `StudentGradeComparator`
• `StudnetIDComparator`
• Here's a simple comparator for strings
```
import Comparator;

/**
* Compares two objects by considering their string representations.
* Does case-insensitive comparison.  Particularly useful for
* comparing strings, but can also be used for other objects.
*
* @author Samuel A. Rebelsky
* @version 1.2 of March 2000
*/
public class StringComparator
implements Comparator
{
/**
* Determines if the string reperesentation of the first object
* is the same as the string representation of the second object.
* Pre: The two objects are initialized and can be converted to strings.
* Post: Returns true if they are equal and false otherwise.
*/
public boolean equals(Object first, Object second)
{
String firstString = first.toString().toLowerCase();
String secondString = second.toString().toLowerCase();
return firstString.equals(secondString);
} // equals(Object,Object)

/* Determines if the string representation of the first object
* should precede than the string representation of the second object.
* One string precedes another iff letters 0 through i-1
* of the two strings are the same and either (i) letter i of the
* first string is less than letter i of the second string or (ii)
* the first string has only i letters and the second string has more
* than i letters.
*/
public boolean precedes(Object first, Object second)
{
String firstString = first.toString().toLowerCase();
String secondString = second.toString().toLowerCase();
// The compareTo operator returns a negative value if
// the first string precedes the second.
return firstString.compareTo(secondString) < 0;
} // precedes(Object,Object)
} // class StringComparator

```

## Common Sorting Algorithms

• Because sorting is such an important task, computer scientists (and normal people, too) have developed a number of techniques that are commonly used for sorting.
• You've already seen one: insertion sort.
• Today we'll consider two others.
• Selection sort is among the simpler and more natural methods for sorting.
• In this sorting algorithm, you segment the array into two subparts, a sorted part and an unsorted part. You repeatedly find the largest of the unsorted elements, and swap it into the beginning of the sorted part. This continues until there are no unsorted elements.
```+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
|
Unsorted           Sorted
```
• Here's my recursive version of selection sort. It is a method of an array-like object that holds a group of information, so the `elementAt` references are to ``the current object''.
```
import Array;
import Sortable;

/**
* Arrays that you can sort using selection sort.
*
* @author Samuel A. Rebelsky
* @version 1.0 of October 1999
*/
public class SelectionSortable
extends Array
implements Sortable
{

// +--------------+--------------------------------------------
// | Constructors |
// +--------------+

/**
* Build a new array which holds up to n elements.
* Initially, each element is null.
*/
public SelectionSortable(int n) {
super(n);
} // SelectionSortable(int)

/**
* Build a new array which holds the specified
* set of elements.
*/
public SelectionSortable(Object[] elements) {
super(elements);
} // SelectionSortable(Object[])

// +-----------------------+-----------------------------------
// | Methods from Sortable |
// +-----------------------+

/**
* Sort all the elements in the array using selection sort.
* Pre: the elements in the array are comparable using
*      a lessEqual method.
* Post: elementAt(i) &lt;= elementAt(i+1) for all 0 &lt;= i &lt; size()-1.
* Post: no element is added to or removed from the subarray.
* Post: no element outside the subarray is affected.
*/
public void sort(Comparator compare)
throws IncomparableException
{
selectionSort(0,size()-1,compare);
} // sort()

// +----------------------+------------------------------------
// | Local Helper Methods |
// +----------------------+

/**
* Sort all the elements in the subarray between lb and ub.
* Pre: 0 &lt;= lb &lt;= ub &lt; size()
* Pre: the elements in the array are comparable using
*      a lessEqual method.
* Post: elementAt(lb) &lt;= elementAt(lb+1) &lt;= ... elementAt(ub).
* Post: no element is added to or removed from the subarray.
* Post: no element outside the subarray is affected.
*/
protected void selectionSort(int lb, int ub, Comparator compare)
throws IncomparableException
{
// Variables
int index;	// Index of the largest element in subrange
// Base case: one element, so it's sorted.  (Don't need to check
// empty subarray because of preconditions.)
if (lb == ub) return;
// Find the index of the largest element in the subrange
index = indexOfLargest(lb,ub,compare);
// Swap that element and the last element
swap(index, ub);
// Sort the rest of the subarray (if there is any)
// Note that we don't have to compare ub-1 to lb, since
//   the preconditions and the base case take care of it.
selectionSort(lb,ub-1,compare);
} // selectionSort

/**
* Find the index of the largest element in a subarray
* Pre: 0 &lt;= lb &lt;= ub &lt; size()
* Pre: the elements in the vector are comparable using
*      a lessEqual method
* Post: returns I s.t. for all i, lb &lt;= i &lt;= ub,
*       elementAt(I) >= elementAt(i)
*/
protected int indexOfLargest(int lb, int ub, Comparator compare)
throws IncomparableException
{
// Variables
int guess;	// Current guess as to index of largest
// Make initial guesses
guess = lb;
// Repeatedly improve our guesses until we've looked at
// all the elements
for(int i = lb+1; i <= ub; ++i) {
if (compare.precedes(get(guess),get(i))) {
guess = i;
} // if
} // for
// That's it
return guess;
} // indexOfLargest
} // SelectionSortable

```
• Here's a class that permits us to test it.
```
import SelectionSortable;
import SimpleOutput;
import StringComparator;

/**
* A simple test of selection sort.
*
* @author Samuel A. Rebelsky
* @version 1.0 of September 1999
*/
public class TestSS {
public static void main(String[] args)
throws Exception
{
SimpleOutput out = new SimpleOutput();
SelectionSortable stuff = new SelectionSortable(args);
stuff.sort(new StringComparator());
for (int i = 0; i < stuff.size(); ++i) {
out.println(i + ": " + stuff.get(i));
} // for
} // main(String[])
} // class TestSS

```
• What's the running time of this algorithm? To sort a vector of n elements, we have to find the largest element in that vector in O(n) steps, and then recurse on the rest. The first recursive call takes O(n-1) steps plus the recursion. And so on and so forth. This makes it an O(n2) algorithm.
• What's the extra memory required by this algorithm (ignoring the extra memory for recursive calls)? It's more or less O(1), since we only allocate a few extra variables and no extra vectors.
• How much extra memory is required for recursive method calls? This is a tail-recursive algorithm, so there shouldn't be any.
• Note that we can also write selection sort iteratively.

### Bubble Sort

• Bubble sort is a lot like both insertion sort and selection sort
• In bubble sort, you step all the way through the array, swapping adjacent elements if they're out of order.
• This ``bubbles'' the largest value to the end.
• Like selection sort, it puts the largest value at the end. It just uses a different technique.
• Like insertion sort, it repeatedly swaps neighboring elements when they're out of order. Unlike insertion sort, it goes all the way through the array.
• The running time is O(n2).

## Choosing a Sorting Method

• All three of these are O(n2). Which should we choose?
• In this case, it turns out that the constants do make a difference. Typically selection sort and insertion sort run much more quickly than does bubble sort.
• Would we ever want to use bubble sort? Yes.
• Sometimes we can only swap neighboring elements. Consider a situation in which you can only store two objects in memory, and the rest in a file. Here's how we might do one round of bubbling up.
```Open the input file
Open a temporary file for the "more sorted" version
Let largestSoFar = the first element in the input file
While (elements remain in the input file)
Let nextElement = the next element in the input file
If nextElement < largestSoFar then
Write nextElement to the temporary file
Else
Write largestSoFar to the temporary file
Set largestSoFar to nextElement
// We've read the whole file (N elements), but only written
// N-1 elements.  Write the last one.
Write largestSoFar to the temporary file
Close the input file
Close the temporary file
Replace the input file with the temporary file
```
• Are there other times we might want to use bubble sort? It turns out that bubble sort is nice on some parallel computers. You can swap a N/2 pairs of adjacent elements in one step
• Round 1: all the cells numbered 2*i swap with 2*i+1 (if out of order)
• Round 2: all the cells numbered 2*i swap with 2*i-1 (if out of in order)
• We'll try acting out this last sorting routine.

## Doing Better

• Can we do better than O(n2).
• It turns out there are O(n log2 n) sorting algorithms.
• What techniques might we apply to develop such algorithms?
• Stay tuned tomorrow for more details.

## History

Tuesday, 18 January 2000

• Created as a blank outline.

Tuesday, 7 March 2000

• Filled in the details. Many are based on outline 25 of CSC152 99F. The section on comparators is new.

Back to Introduction to Sorting. On to More Efficient Sorting Algorithms.

Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.