Computer Science 60
Principles of Computer Science
Spring 2014


Assignment 9: Sorting out Big-O    [100 Points]
Due Tuesday, November 18th by 11:59pm

This week's homework includes big-O analysis of software, first through loop-counting (analysis of iterative algorithms) and recurrence relations (analysis of recursive algorithms). The second part asks you to implement some of the best-designed algorithms for CS's most-studied task: sorting, including an "impossible" Big-O(N) sorting algorithm.


Partners: 

This week's problems may be done singly or in a pair. If you do work in a pair, be sure to adhere to the pairwork guidelines of (1) equal hands-on and oversight contributions to the work and (2) equal understanding of the submitted assignment.



Problem 1: Big-O running times...

40 points

This homework is available on paper and you may not share this homework assignment with anyone outside of the class (it has solutions from previous assignments). You can get a copy of this part of the homework:

You will self report on the top of the homework when you completed the assignment, which we'll use to see if you completed the assignment on-time. If you indicate that you completed the assignment before the due date Tuesday 11:59pm, it will be considered "on-time." You can turn in this homework after the Tuesday due date:

Problem 2: Sorting in Racket and Prolog

20 points

For this problem, you'll implement parts of the two "classical" sorting algorithms in both Racket and Prolog: selection sort and insertion sort. In each case, use the starter files sort.rkt and sort.pl.

Selection sort is the algorithm in which either the max or the min value is repeatedly found and removed from a list - and added to a new, sorted list in the appropriate order. For this assignment, you'll implement minsort, i.e., the selection each time should be the minimum element.

Insertion sort is, in a sense, the dual approach: rather than find the correct next-element to place into the new list (as in minsort, above), the algorithm repeatedly removes the first element from the original list and inserts it into the growing sorted list in the right spot. In this case the work is done in that insertion step: getting the new element into the right place.

Each of these files has some scaffolding (to make sure that it's actually selection sort and insertion sort being implemented. Each also has a number of tests to check your sorting algorithms. Here are those starter files -you'll need to change the name of sort.txt to sort.pl:

Writing additional tests is welcome here (and always a good idea), but we will not be checking for those during the grading. Submit these files as sort.txt and sort.pl to the usual place in the submission system.



Problem 3: Minsort, Heapsort, and Bucketsort: Java

40 points

For this problem, you should use the starter file Sort.java that is linked here:

This file has a wrapper class named Sort. There, you'll implement the static methods minsort, heapsort, and bucketsort, which are O(N**2), O(NlogN), and O(N) sorting algorithms, respectively. Because they're static, they don't need you to create an Object of type Sort. Rather, they can simply be called as ordinary functions on arrays of integers. Each of the sorting algorithms is meant to sort in-place or "destructively," in the sense that the input array should be changed by the algorithm. It is completely OK to create a new array, sort the elements into it (in the appropriate way) and then copy them back into the input array.

If you're getting an error about the static keyword, you may have a slightly earlier version of Java -- no worries! To fix this,



minsort is as described above. Here, there are two primary methods for implementing minsort (though variations are welcome):



bucketsort is as described in class (on Thursday). It's also commonly called "counting sort." Here's a reminder/illustration of the algorithm:


With this in mind, you will definitely need to make a separate array (perhaps called buckets) in order to hold the count of each distinct element. As noted, you will need to do some initial computation to find how many buckets are necessary! This will depend on the value of the min and max elements in the original list.

Be careful as you take things out of the buckets -- empty buckets can be tricky! As part of this implementation, we ask that you not simply allocate "a lot" of buckets - rather, you should determine the number of buckets needed, based on the min and max values in the input array, and then use that number.



heapsort is already implemented in Sort.java. Like make fast algorithms, it uses a clever data structure in order to achieve its efficiency -- your task is to implement the Heap data structure, which will ensure that heapsort runs as intended. Your Heap class has a single data member, which is a resizable array known as an ArrayList in Java. Since your ArrayList will contain integers, its full datatype is ArrayList<Integer>. This whole name is the name of the type of the data member heapdata.

Although the above description shows there's some overhead to using Java's ArrayList class, there are many advantages. Here are some of the methods provided by Java's library that you'll need to write percolate:

The percolate algorithms

Recall that each of these two algorithms strives to maintain the "heap property" that each node in the heap is less than its one or two children:

With those methods, you should implement the percolate_up() and percolate_down() methods in the Heap class. the appropriate length, then implement the repeated min-finding to that new array, and then run a short loop to copy the elements back to the original array.

The file SortTest.java, above, has tests for each of those sorting implementations. One note: the graders will not only be looking to see that your submission passes the tests, but that they implement the specified sorting algorithm. Java does have Arrays.sort built-in - in fact, we use it in the tests file, but don't use it to implement these sorting methods... !

Submit your Sort.java in the usual way.

As with the Racket and Prolog files, writing additional tests is welcome, but we will not be checking for those - so you will not need to submit the tests file in this case.



Extra credit...

There are two entirely optional extra-credit challenges this week:


Improved StoogeSort!

The first optional - and challenging! - extra-credit problem worth up to +5 points is to write a recurrence relation and solve it for the Stooge's improved StoogeSort. Improved StoogeSort does the following:

First, explain in a sentence or two why Improved StoogeSort actually sorts successfully! Next, write a recurrence relation for this Improved StoogeSort algorithm. Finally, "unwind" that recurrence relation and simplify it to state the overall big-O running time of improved stooge sort? Also, note in a sentence whether this algorithm is polynomial or exponential and whether it's better or worse than the original StoogeSort.

Place your answer at the bottom of hw9pr1.txt at the bottom of the other part 1 solutions. Note that if you find the result irrational, you may have gotten it! This one requires handling a more intricate geometric series... .


Quicksort!

The second extra-credit option (again, up to +5 points) is to implement quicksort in Java. The signature provided in the file is

public void quicksort( int[] A )
but you will find it useful to delegate most of the work to a helper function
public void quicksort( int[] A, int low, int hi )
which sorts, in-place, all of the elements in A whose indices run from low to hi, inclusive. Feel free to use the first element as the "pivot." This does lead to slower asymptotic runtimes of O(N**2) when the original list is sorted, but that's OK for this implementation.

One of the advantages of quicksort is not only that it's fast, but that it can be written to avoid the use of any additional arrays! So, for this implementation, do not use any additional allocations of arrays -- simply use local variables (single ints) and the provided array A. Warning: be sure your implementation always creates recursive calls whose size is smaller than the original call -- one common implementation bug is caused by recursing infinitely (well, until the stack runs out!)

There are tests in SortTest.java to test quicksort; again, the graders will take a look that it's actually quicksort that you've implemented! :^)