Description
Implement the three sorting algorithms discussed in class and provide experimental evaluation and analysis of their running times.
Create a project called
SortAlgos
with the classes mentioned below.
Javadoc API is not required.
Generic Methods
Some of the methods below are generic but they are not part of a generic class. To declare a generic method, simply put <E> in front of the return type. Here is an example:
public <E> void printArray(E[] items)
{
}
The Tester
See Section
JUnit below on how to setup the Tester.
Swaps and Comparisons
Download the
SortUtils.jar
file in the
SortAlgos
project folder (next to folders
bin/ src/
):
To swap the values at two indices in a primitive array:
SortUtils.swap( the-array-name, i, j)
To compare two values:
if ( SortUtils.compare(xxx, yyy) < 0 ) instead of if ( xxx < yyy )
if ( SortUtils.compare(xxx, yyy) > 0 ) instead of if ( xxx > yyy )
if ( SortUtils.compare(xxx, yyy) == 0 ) instead of if ( xxx == yyy )
Max Heap
Implement generic class
MaxHeap
with the methods given below. The data members are:
items
-- the primitive array of items managed by this
heap; this array is provided externally
size
-- the size of the heap
MaxHeap(E[] theItems)
Creates a max heap from the given items. The size is initially the same as the number of items in the array.
|
void pushDown(int i)
(private) Pushes the item at the given index down the items array (down the heap) until it ends up in a place where it has no max-heap property violations with its children.
This method repairs the heap starting from the given index and is used in most of the methods that follow.
Zig-zag down the tree exchanging with the larger child. Stop when no max-heap property violation.
You may assume that the heap is not empty
|
void makeHeap()
(private) Rearranges the data member items so that it represents a max heap.
Repair the heap starting at the farthest non-leaf and moving up toward the root.
Initially start at the very last item, since this is easier. Then think of the formula that can compute the location of the farthest non-leaf from the heap size.
No if -statements. It should be possible to create an empty heap without any extra code.
|
E pop()
Returns (and removes) the max value in the heap.
The max is always at the top of the heap. Replace the max with the last item and repair the heap from the top.
Note: Since we will be comparing the execution time of sorting algorithms, you may assume that the heap is not empty to avoid the constant check. (Normally, this would have to be handled.)
|
isLeaf(int i)
(private) Determines if the item at the given index is a leaf.
You may assume the heap is not empty and the index is valid.
Do as little work as possible to determine the answer.
|
left(int i), right(int i)
(private) Returns the child index.
|
toString()
Returns a string representation of this heap (up to its size). This method is given:
public String toString()
{
return SortUtils.toString(items, size);
}
|
Heap Sort
Create class
HeapSort
that implements the
HeapSort algorithm.
- all methods in this class are
static
- the class
HeapSort
is not generic, but its methods are generic
void sort(E[] items)
The method sorts the given items using the Heap Sort algorithm discussed in class:
- create a max heap out of the items
- pop the max element from the heap and store it at the end of the given array; each time we pop from the heap a new spot opens up
- repeat as many times as needed to put each item in its correct spot; avoid unncessary work
|
Quick Sort
Create class
QuickSort
that implements the
QuickSort algorithm.
- all methods in this class are
static
- the class
QuickSort
is not generic, but its methods are generic
int partition(E[] items, int i, int j)
Partitions the items in the given range [i,j] (inclusive) around
a pivot. The method returns the index where the pivot element ends up after the partition.
Initially pick the middle element in the given range to serve as the pivot, so that it is easy to test/debug the code.
For the final comparison use method median3 from SortUtils . This method will place the median of first, middle, and last items in the middle index.
Briefly, here is how the partition algorithm works:
- pick a pivot element and swap it with the last item in the range
- move forward index
i until it finds an item bigger than the pivot
- move backward index
j until it finds an item smaller than the pivot
- exchange the values at
i, j
- repeat steps 2-4 until
i,j meet
- exchange the pivot and the item at index i; this puts the pivot in its
proper spot
Note: You may assume that the range is not empty. This will have been ensured elswhere.
|
void sort(E[] items, int i, int j)
Sorts the items in the given range [i,j] (inclusive) using the QuickSort algorithm.
Briefly, here is how QuickSort works:
- partition the given range
- sort each "half" of the range (i.e. each side of the pivot)
Note that the partition algorithm will have put the pivot in its correct spot.
|
void sort(E[] items)
Sorts the given items using the QuickSort algorithm. This method simply calls the previous one.
|
Merge Sort
Create class
MergeSort
that implements the
MergeSort algorithm.
- all methods in this class are
static
- the class
MergeSort
is not generic, but its methods are generic
E[] merge(E[] leftSide, E[] rightSide)
Merges the two primitive arrays into a final sorted primitive array. The given sides are assumed to have already been sorted.
Briefly, here is how the merge algorithm works:
- create the result primitive array with enough space to hold both sides
- keep two indices starting at the beginning of each side (and an index into the result)
- transfer to the result the smaller element from the two sides and advance the corresponding index
- at the end transfer the left over elements from one of the sides
Note: As part of the sorting algorithm will need to create arrays of certain sizes. See method copyCell and arrayAs in SortUtils .
|
E[] sort(E[] items, int i, int j)
Returns a sorted array of the given range [i,j] (the given array
is not modified) using the MergeSort algorithm.
Briefly, here is how MergeSort works:
- find the middle index and sort each half
- merge the results from the previous step
Note: As part of the sorting algorithm will need to create arrays of certain sizes. See method copyCell and arrayAs ins SortUtils .
Note: You may assume that the range is not empty, but put as a comment what you would have written if this assumption was not allowed.
|
E[] sort(E[] items)
Returns a sorted array of the given items (the given array is not modified) using the MergeSort algorithm. This method simply calls the previous one.
Note: You may assume that the array is not empty.
|
JUnit Tests
Create class
SortAlgosTest
that shows evidence of thorough testing. Here is an example:
numbers = load( ...the numbers... );
numbers = MergeSort.sort(numbers);
assertEquals(SortUtils.toString(numbers), "[...the expected result...]");
In particular:
- the Tester will have at least one array data member and the following
load
method:
public static <E> E[] load(E... items)
{
return items;
}
- make sure to put
@Test
in front each method of the Tester
- create method
test_Heap()
and test
- the non-private methods of the heap (you should be able to create an empty heap, but do not test
pop() for it)
- create method
test_HeapSort()
and test
sort(items)
with empty, single, two, many; for each configuration try increasing (sorted), random, and descending (in reverse)
sort(items)
with String-array for the many configuration with increasing (sorted), random, and descending (in reverse)
- create method
test_QuickSort()
and test
partition(items, i, j)
with a fixed array, but a few [i,j]
ranges to test the standard interesting configurations
sort(items)
with empty, single, two, many; for each configuration try increasing (sorted), random, and descending (in reverse)
sort(items)
with String-array for the many configuration with increasing (sorted), random, and descending (in reverse)
- create method
test_MergeSort()
and test
merge(leftSide, rightSide)
with a few inetersting combinations; note that two sides are assumed to be sorted
sort(items)
with empty, single, two, many; for each configuration try increasing (sorted), random, and descending (in reverse)
sort(items)
with String-array for the many configuration with increasing (sorted), random, and descending (in reverse)
Algorithm Comparison
This portion may be submitted on Friday (there will be a separate dropbox). Create class
CompareSortAlgos
with the following methods:
standard main
-- simply calls the next method three times for "sorted", "reverse", "random"
configurations
void compareSortAlgos( int initSize, int finalSize, int sizeStep, String order )
This method generates a table of execution times for the three algorithms for arrays of various sizes. The first three parameters specify an initial array size, a final array size, and a size increment, and the last parameter is one of the characters "sorted", "reverse", "random"
to specify what configuration to test.
For example, if we execute compareSortAlgos(2000, 14000, 3000, "random")
the method:
- generates arrays of sizes
2000, 5000, 8000, 11000, 14000
- sorts the arrays with the three sorting algorithms
- displays how many milliseconds each algorithm took
- (the arrays will have random numbers since
"random"
was given)
- make sure to run each sorting algorithm on its own array of the given size; that is, make sure not to sort an array that has already been sorted
- method
generateArray(...)
from class SortUtils
is used to generate an array of a given size and for a given configuration
Here is the format of the table. Each row starts with current size followed by the times for the three algorithms:
2000 50 37 42 ← SIZE QSms HSms MSms
5000 70 48 57
8000 95 72 80
11000 120 90 105 ← timing numbers are made up
14000 143 123 130
Here is how to find the execution time (in milliseconds) of a code section:
long start = System.currentTimeMillis();
bubbleSort(someArray);
long stop = System.currentTimeMillis();
long time = stop - start;
Summary of Results
Make sure to add the -Xint
flag under "VM Arguments":
1) Right-click on project name; Go to "Run As" -> "Run Configurations"
2) [Left Panel] Click on "Java Applications" -> "SortAlgos"
3) [Right Panel] Click tab "Arguments" and in box "VM Arguments" write -Xint
Do this part when all sorting algorithms work correctly and you are ready to collect the time measurements that will be plotted in Excel.
Generate three tables (one for each configuration) for testing arrays of sizes 100,000--1,000,000 (inclusive) at size increments of 100,000.
Using Excel create a single document with three sheets for each input configuration --
sorted,
reverse sorted, and
random order input array.
- Save the document in a single file called CompareSortAlgos.xlsx with three sheets inside called Sorted, Reverse, and Random.
- Each plot should show the relationship between input size (x-axis) and run-time (y-axis) for the three sorting algorithms on the respective input configuration. Here are instructions on how to draw an XY-Scatter Chart in Excel is available.
- Fit a curve/trendline through the data for each algorithm for each plot. Use your judgment as to what curve is the best fit. Excel will allow you to fit a straight line, any polynomial curve (i.e.
n?
), exponential curve, etc. Our analysis from class suggested a polynomial trendline of either degree 1 or degree 2.
- Show the equation for each curve/trendline. Here are instructions on how to fit a trendline in Excel.
- In the Excel file provide a brief explanation of your findings. State which algorithm you expected to be faster, briefly explain why, and state whether the data supports your expectations.