Homework 7: All Sorts of Fun!

This homework is intended to give you a chance to better understand sorting. Here is the introduction video.

A. Implementing Sorting Algorithms

The skeleton, MySortingAlgorithms.java provides a template for implementing various sorting algorithms.

Open SortingAlgorithm.java to see the interface you will have to satisfy. Note that every child class's sort method takes in an argument k. The sorting algorithm should sort the array from index 0 to k. Hint: This argument could be useful for some of your sorts.

Implement the algorithms below (the ones with an asterisk next to it are required for this assignment). Note that an implementation of Quicksort.java has been provided. Clicking on the links will take you to an animation of the sort to refresh your memory.

Watching these videos is not mandatory, but they are linked to help your conceptual understanding for this assignment! If you don't like videos, these slides also have step-by-step breakdowns for each algorithm.

Conceptual videos:

You can use MySortingAlgorithmsTest.java to test your implementations.


Once you're done, here are some questions to ponder (you don't need to record nor submit your responses):


Additionally, the RunBenchmarks class runs timing tests on our various sorts. Currently, it is configured to perform two timing tests:

Run the code, and you should see results that are in line with things we've learned in class.

If the second test takes too long to complete, you can "Edit Configurations" in IntelliJ and type a number for program arguments to run the test on a smaller input size.

Other interesting tests you might try:

Feel free to post interesting tests and/or observations on Piazza. You do not need to submit anything related to this Benchmark test.

B. Sorting Problems

There are many problems for which sorting provides a fast solution, even though the problem isn't really about sorting. We encourage you to do all of these, but you only need to do any one of them for full credit. All of the questions below are really common coding interview questions, if that's a motivating factor for you!

Intervals (Intervals.java)

Define an interval to be a pair of numbers $[x_i, x_j]$ such that $x_i < x_j$. An interval specifies a range of values in 1D space, where we can call $x_i$ the start point, and $x_j$ the end point.

Given a list of such intervals, we want to know the total length of the regions covered by one or more of the intervals. This is not simply the sum of their lengths, $\Sigma x_j - x_i$, since several may cover the same span.

For example, if we have intervals $[19, 30]$, $[6, 12]$, $[4, 5]$, $[8, 15]$, and $[3, 10]$, then the total length covered is 23: the last four intervals together totally cover the interval $[3, 15]$ of length 12, and the first covers a disjoint interval of length 11.

Fill in Intervals.java so that the coveredLength method returns the correct total length in $\Theta(N log N)$ time.

There is a clever trick to this problem that you'll need to figure out to get $\Theta(N log N)$ time. You do not need to use any nested loops for this problem, and in fact if you find yourself using them, you probably haven't found the right approach.

Note that you may want to use Lists.sort(Comparator<? super E> c) or Collections.sort(List<T> list, Comparator<? super T> c). for this problem! If you find yourself using either of these, remember that you can define an inner class that implements the Comparator interface.

Distribution Count for Large Numbers (SortInts.java)

[Goodrich & Tamassia] Given a sequence of n distinct integers, each one of which is in the range $[0, n^2 - 1]$, develop an $O(n)$ algorithm for sorting them. See the skeleton file SortInts.java. You can't use ordinary distribution sort for this, because that would require initializing and traversing arrays of size $n^2$, which would take too long

Inversion Counting (Inversions.java)

Find an algorithm that runs in $O(n \lg n)$ time for computing the number of inversions in a list of n items. Array elements that are "out of order" can be corrected by swapping two adjacent elements at a time, each of which counts as a single inversion. See the skeleton file Inversions.java. To test that your code is actually $O(n \lg n)$, provide it a very large list (say hundreds of thousands).

Two Sum (Sum.java)

[Goodrich & Tamassia] Given two sequences of integers, $A$ and $B$, find an algorithm that runs in $O(n \lg n)$ time (where n is the total number of integers in A and B) that determines, for a given parameter $m$, whether there is an integer $a$ in $A$ and an integer $b$ in $B$ such that $m = a + b$. See the skeleton file Sum.java. To test that your algorithm runs in $O(n \lg n)$ time, provide sequences of hundreds of thousands of integers. Feel free to use any of the methods in java.util.Arrays.

C. Quicksort Mechanics (Optional)

Interestingly enough, quicksorting an array is equivalent to inserting all of its items into a BST. In this problem, we'll see why.

First, we need a specific implementation for partitioning.

Consider the array [5, 3, 2, 1, 7, 8, 4, 6], and suppose that we pick the leftmost item 5 as our pivot. One approach to partitioning is to perform a "stable" partitioning where all items that are less than 5 appear in the same order as they did before partitioning, and likewise for the greater items. For the given array, we'd get [3, 2, 1, 4, 5, 7, 8, 6].

One inefficient but simple way to implement this stable partitioning algorithm is to perform the following steps:

So for example if we partition [5, 3, 2, 1, 7, 8, 4, 6] from index 0 to index 7, we'd get:

Smaller items: [3, 2, 1, 4]
Equal items  : [5]
Larger items : [7, 8, 6]

The concatenation of these lists is just [3, 2, 1, 4, 5, 7, 8, 6]. Along the way, we compared the following pairs of numbers: 5-3, 5-2, 5-1, 5-4, 5-7, 5-8, and 5-6.

If we are using partition to sort, we then repeat this process for the left half and right half sides as discussed in class.

  1. Try to write out the rest of the list of comparisons used by Quicksort. You might find running the provided Quicksort.java to be useful. The order of the pair does not matter (5-3 is equivalent to 3-5). You may also want to draw the BST that results when you insert [5, 3, 2, 1, 7, 8, 4, 6] (in that order) into an initially empty BST.
  2. List all comparisons performed when inserting [5, 3, 2, 1, 7, 8, 4, 6] into a BST. Give your comparisons in the order they occur, writing the pivot first. Put only a comma and a space between pairs. The first few have been provided for you, so you should not include them in your answer: 5-3, 5-2, 3-2, ...
  3. What do you observe about the list of comparisons done by Quicksort vs BST insertion?

You can highlight (drag your mouse over) the following whited-out text to see the answers:

  1. In addition to the comparisons with 5 that we saw earlier, we also do all of 3-2, 3-1, 3-4, 2-1, 7-8, 7-6.
  2. 5-1, 3-1, 2-1, 5-7, 5-8, 7-8, 5-4, 3-4, 5-6, 7-6
  3. They have the same comparisons, though they're done in a different order!

D. Submission

You will be required to submit:

  1. MySortingAlgorithms.java with Selection Sort, Insertion Sort, Mergesort, and LSD Radix Sort implemented.
  2. At least one of Intervals.java, SortInts.java, Inversions.java, and Sum.java. (We suggest you attempt all of them, however.)

Don't forget to push both your commits and tags for your final submission. As a reminder, you can push your tags by running:

$ git push --tags