Sorting (Due Monday, April 20th)
For your third project, you will implement a number of sorting algorithms, and then test their performance. This project will consist of not just coding, but also testing your code using large data sets. Note that when all of your code is complete and debugged, you still have a fair amount of work to do -- so start early!Coding Sorting Algorithms
For Part 1 of the assignment, you will need to write 12 sorting algorithms: Insertion Sort, Selection Sort, Shell Sort, Bucket Sort, Heap Sort, Radix sort, and Quick sort (2 versions), as well as a version of selection sort, merge sort, and insertion sort that work on linkned lists. Your sorting project will contain:- Sorting class interface (provided)
- Linked List element class (provided)
- Sort class, which implements the interface class
- SortTest class which contains your main program
- Your sorting class be named Sort
- Your Sort class has a constructor that takes no parameters
- Your Sort class implements the interface as is, without changes.
Efficiency Testing
After you have coded your algorithms, you need to test them, to see how long each sorting algorithm takes to run. You should test each algorithm on both random and sorted lists of sizes 1000, 5000, 10000, 50000, 75000, 100000 and 500000. You can get a random list using the java class Random, located in java.util.Random To test the speed of your sorting algorithms, you should use the System.currentTimeMillis() method, which returns a long that contains the current time (in milliseconds). Call System.currentTimeMillis() before and after the algorithm runs, and subtract the two times. Unfortunately, using currentTimeMillis before and after a function only gives an accurate time estimate if the function takes a long time to run (that is, at least a couple of seconds). Since running some sorting algorithm on a list of size 1000 will take a very short time, you will need to do something like the following:long startTime, endTime;
double duration;
Random randomGenerator = new Random();
Sort sorter = new Sort();
startTime = System.currentTimeMillis();
for(i=0;i<NUMITER;i++) {
for (j=0; j< listsize; j++)
list[j] = randomGenerator.nextInt();
sorter.quickSort(list,0,listsize-1));
}
}
endTime = System.currentTimeMillis();
duration = ((double) (endTime - startTime)) / NUMITER;
You'll have to play around with different values for NUMITER -- it will need to change depending upon the size of the list and the algorithm.
You might notice that there is some non-sorting work done in the above algorithm -- mainly, setting up the list before each sort can take place. This work takes a small amount of time in comparison to the sorting, as you can easily check for yourself:
startTime = System.currentTimeMillis();
for(i=0;i<NUMITER;i++) {
for (j=0; j< listsize; j++)
list[j] = rand();
}
endTime = System.currentTimeMillis();
duration = ((double) (endTime - startTime)) / NUMITER;
You should subtract this setup time from your algorithm running time, to get more accurate results. Your main program may run in either interactive mode or batch mode (though you do not need to implement both modes, just the one that is easiest for you to use in testing.)
Building a Better Sorting Algorithm
When the list get large, quicksort is clearly the fastest comparison sorting algorithm (hence the name). However, when the lists are small enough, quicksort runs slower that some of the Θ(n2) algorithms. This might not seem important until you note that when sorting a large list with quicksort, many many small sublists must be sorted. While the savings on sorting one small list with a faster algorithm is negligible, sorting hundreds of small lists with a faster algorithm can make a difference in the overall efficiency of the sort. For part 3 of the assignment, you will combine quicksort with another sorting algorithm to build the fastest possible sorting algorithm. You have several options --- Use quicksort until the list gets small enough, and then use another sort or insertion sort to sort the small lists
- Use quicksort to "mostly" sort the list. That is, use quicksort to sort the list until a cutoff size is reached, and then stop. The list will now be mostly sorted, and you can use insertion sort on the entire list to quickly complete the sorting (not unlike the strategy used in Shell Sort)
- Use some other method of your own devising.
Sorting Algorithms in Detail
- public
void insertionSort(Comparable[] array, int lowindex, int highindex, boolean
reversed)
This is the most straightforward of the sorting algorithms to code - there are only two wrinkles -- your insertion sort needs to work over a range of indices in the array, just like quicksort, and you need to be able to sort the list backwards, if the reversed flag is true. Your algorithm should sort all elements in the array in the range lowindex..highindex (inclusive). You should not touch any of the data elements outside the range lowindex .. highindex. Note that you need to be able to sort any Comparable object, not just ints. - public
void selectionSort(Comparable[] array, int lowindex, int highindex, boolean
reversed)
Also very straightforward. As with insertion sort above, your sorting algorithm needs to work over a range of indicies in the array, and you need to be able to sort the list backwards, if the reversed flag is true. Your algorithm should sort all elements in the array in the range lowindex..highindex (inclusive). You should not touch any of the data elements outside the range lowindex .. highindex.
- public
void shellSort(Comparable[] array, int lowindex, int highindex, boolean
reversed)
Your implementation of Shell Sort needs to use Hibbard's increments - 1, 3, 7, 15, ... 2k-1. Thus if the range of elements contains 100 elements, the first sort would be a 63-sort, followed by a 31-sort, 15-sort, 7-sort, 3-sort and 1-sort. (The code in the notes uses Shell's increments - in this case 50, 25, 12, 6, 3, 1). As with insertion sort, you need to be able to sort only a range of the array, and also be able to inverse-sort the array.
- public
void bucketSort(int[] array, int lowindex, int highindex, boolean
reversed)
Your implementation of Bucket Sort should use half as many buckets are there are elements to be sorted. Thus, if highindex - lowindex + 1 == 100, you should use 50 buckets. Assume that the data values are evenly distributed over the range of the list. You will need to do a quick run through the list to find the range of values stored in the list. You need to be able to handle sorting negative as well as positive values. While the list that you are sorting will be ints, you might need to use longs in some places when calculating bucket size. As before, you need to be able to inverse-sort the list. Note that you are sorting ints here and not Comparables -- bucketSort is not a comparison-based sorting algorithm!
- public
void heapSort(Comparable[] array, int lowindex, int highindex, boolean
reversed)
As with insertion sort, you need to sort a range of indices. Do not copy the range to be sorted into a temporary array, sort it, and then copy back -- you need to sort the data in place You also need to be able to inverse sort the list.
- public
void quickSort(Comparable[] array, int lowindex, int highindex, boolean
reversed)
This is the standard, unmodified version of quicksort. You should use a median-of-three to pick the pivot. That is, pick three elements (first, middle, and last, or three random) and use the median of those 3 elements as the pivot. This version of quicksort should not be a hybrid. Note that you will need to do some special-case work on small lists (since obviously you cannot find the median of three on a list with 2 elements)
- public
void radixSort(int[] array, int lowindex, int highindex, boolean
reversed)
As with all of the other sorting algorithms, radix sort needs to be able to sort elements in the range lowindex to highindex. The notes use base-10 for radix sort -- for this assignment, you should use base-n, where n is the number of elements in the list to be sorted (that is, highindex - lowindex + 1)
- public
LLNode insertionSortLL(LLNode list, boolean reversed)
This function uses Insertion Sort to sort a linked list. It should be called in a similar fashion to tree functions, as follows:
A = insertionSortLL(A, false);
Note that when using linked lists, you need to implement insertion sort in a slightly different way (for instance, an inverse sorted list will probably give best-case performance, while a sorted list will probably give you worst-case performance)
- public
LLNode mergeSortLL(LLNode list, boolean reversed)
Much as above, this function sorts a linked-list using merge sort. You should not allocate any extra memory for this version of merge sort (no calls to new!) Instead, you need to rearrange the linked list elements that are passed in.
- public LLNode
selectionSortLL(LLNode list, boolean reversed);
Much as above, this function sorts a linked-list using selection sort. You should not allocate any extra memory for this version of selection sort (no calls to new!) Instead, you need to rearrange the linked list elements that are passed in.
- void
optimizedQuickSort(Comparable array[], int lowindex, int highindex, boolean
reversed)
This should be a hybrid of quicksort and some other sorting algorithm. Make it as efficient as possible.
What to Turn In
You need submit electronically- Source code for all of your sorting algorithms
- Source code for your main program, which you used for the performance testing
- A .pdf file containing running times for all 11 algorithms (8 standard, 2 linked-list versions, 1 optimized quicksort) for lists of , 200, 1000, 5000, 10000, 50000, 75000, 100000 and 500000. Be sure to subtract out the overhead time costs! You should include sorted and inverse sorted lists as well as random lists for each list size in these tests. The results should not be handwritten and scanned! Use your favorite word processor / spreadsheet / etc instead, and print to .pdf
- A brief (one page is enough) .pdf document on how you created your
hybrid sorting algorithm -- which apporoaches you tried, what different
parameters you chose, and how much of a difference these changes made
to the efficiency of your algorithm.
https://www.cs.usfca.edu/svn/<username>/cs245/Project3/