Add lots of documentation

This commit is contained in:
Kumiho 2018-04-30 23:04:43 +02:00
parent eec221506b
commit c55a7ecb6d
4 changed files with 99 additions and 28 deletions

View File

@ -5,59 +5,114 @@ import frame.SortArray;
/**
* Abstract superclass for the Quicksort algorithm.
*
* Note: I got into a small optimization competition with a fellow student, trying
* to get read and write ops to an absolute minimum. While this code does not include
* most of the write optimizations for the sake of legibility, there is a fair bit of
* passing local variables between functions to save a few read ops.
* I do believe this to be well within the rules of the assignment as values are not
* cached in an array-like structure or passed between recursion levels.
* All optimizations merely cut down on duplicate / unnecessary reads and writes.
*
* @author NAJI
* @author Nils Rollshausen
*/
public abstract class QuickSort {
// DO NOT modify this method
public abstract void Quicksort(SortArray records, int left, int right);
// You may add additional methods here
/**
* Partitions an interval of the SortArray so that elements of the left part are <= pivot
* and elements on the right are >= pivot. This variant does not use any pre-cached values for array bounds
* @param pivot The value of the pivot element
* @param records The SortArray to partition
* @param leftBound Left bound index of the interval to partition
* @param rightBound Right bound index of the interval to partition
* @return index of the partition
*/
protected int partition(SortingItem pivot, SortArray records, int leftBound, int rightBound) {
if(leftBound == rightBound)
return leftBound;
// Lookup bound values
SortingItem leftValue = records.getElementAt(leftBound);
SortingItem rightValue = records.getElementAt(rightBound);
// Use actual implementation with pre-cached bound values
return partition(pivot, records, leftBound, rightBound, leftValue, rightValue);
}
/**
* Partitions an interval of the SortArray so that elements of the left part are <= pivot
* and elements on the right are >= pivot. As the value of the leftmost array element is
* equal to the pivot value when using said element as the pivot, we can avoid reading that
* value from the array _again_ by passing it as an additional parameter
* @param pivot The value of the pivot element
* @param records The SortArray to partition
* @param leftBound Left bound index of the interval to partition
* @param rightBound Right bound index of the interval to partition
* @param leftValue Value of the element at index leftBound
* @return index of the partition
*/
protected int partition(SortingItem pivot, SortArray records, int leftBound, int rightBound, SortingItem leftValue) {
if(leftBound == rightBound)
return leftBound;
// Look up the right bound value
SortingItem rightValue = records.getElementAt(rightBound);
// Use actual implementation with pre-cached bounds
return partition(pivot, records, leftBound, rightBound, leftValue, rightValue);
}
/**
* Partitions an interval of the SortArray so that elements of the left part are <= pivot
* and elements on the right are >= pivot. As the value of the bounding array elements is
* already known in some usecases, we can avoid reading these values from the array again
* by passing them as additional parameters
* @param pivot The value of the pivot element
* @param records The SortArray to partition
* @param leftBound Left bound index of the interval to partition
* @param rightBound Right bound index of the interval to partition
* @param leftValue Value of the element at index leftBound
* @param rightValue Value of the element at index rightBound
* @return index of the partition
*/
protected int partition(SortingItem pivot, SortArray records, int leftBound, int rightBound, SortingItem leftValue, SortingItem rightValue) {
if(leftBound == rightBound)
return leftBound;
int leftIndex = leftBound;
int rightIndex = rightBound;
SortingItem temp;
/*
* Using the Hoare partitioning scheme here as opposed to the one presented in the lecture
* for approximately three times less swap operations compared to the Lomuto scheme
* See https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme for details
* Essentially, increment / decrement left / right indices until a pair of values that are
* the wrong part of the list is found, then swap that pair and continue
*/
while(true){
// As long as the items at left index are smaller than the pivot, they are on the right side
while(leftIndex < rightBound && leftValue.compareTo(pivot) < 0) {
leftIndex += 1;
leftValue = records.getElementAt(leftIndex);
}
// Same for items at rightIndex larger than the pivot
while(rightIndex > leftBound && rightValue.compareTo(pivot) > 0) {
rightIndex -= 1;
rightValue = records.getElementAt(rightIndex);
}
// As soon as both indices cross, no more swaps have to be made and the partition is complete
if(leftIndex >= rightIndex) {
return rightIndex;
}
// If the indices are not equal (or crossed over), swap the two items that are in the wrong spot
records.setElementAt(leftIndex, rightValue);
records.setElementAt(rightIndex, leftValue);
// Also swap the local copies
temp = rightValue;
rightValue = leftValue;
leftValue = temp;

View File

@ -8,24 +8,23 @@ public class QuickSortA extends QuickSort {
* Quicksort algorithm implementation to sort a SorrtArray by choosing the
* pivot as the first (leftmost) element in the list
*
* @param records
* - list of elements to be sorted as a SortArray
* @param left
* - the index of the left bound for the algorithm
* @param right
* - the index of the right bound for the algorithm
* @param records List of elements to be sorted as a SortArray
* @param left The index of the left bound for the algorithm
* @param right The index of the right bound for the algorithm
* @return Returns the sorted list as SortArray
*/
@Override
public void Quicksort(SortArray records, int left, int right) {
// implement the Quicksort A algorithm to sort the records
// (choose the pivot as the first (leftmost) element in the list)
// Lists of length 1 or smaller are trivially sorted
if(right - left < 1)
return;
// Use the leftmost element as the pivot
SortingItem pivot = records.getElementAt(left);
// Pass the value of the pivot as the leftValue to partition to save an array read
int p = partition(pivot, records, left, right, pivot);
// Sort the two sub-lists recursively (p being the position of the partition)
Quicksort(records, left, p);
Quicksort(records, p+1, right);
}

View File

@ -8,52 +8,64 @@ public class QuickSortB extends QuickSort {
* Quicksort algorithm implementation to sort a SorrtArray by choosing the
* pivot as the median of the elements at positions (left,middle,right)
*
* @param records
* - list of elements to be sorted as a SortArray
* @param left
* - the index of the left bound for the algorithm
* @param right
* - the index of the right bound for the algorithm
* @param records List of elements to be sorted as a SortArray
* @param left The index of the left bound for the algorithm
* @param right The index of the right bound for the algorithm
* @return Returns the sorted list as SortArray
*/
@Override
public void Quicksort(SortArray records, int left, int right) {
// implement the Quicksort B algorithm to sort the records
// (choose the pivot as the median value of the elements at position
// (left (first),middle,right(last)))
// Lists of length 1 or smaller are trivially sorted
if(right - left < 1)
return;
// Get the left and right bounding values (for median calculation)
SortingItem leftValue = records.getElementAt(left);
SortingItem rightValue = records.getElementAt(right);
// Calculate the median pivot of left, right and middle
SortingItem pivot = getPivot(left, right, records, leftValue, rightValue);
// Pass the already looked-up left and right values to partition to save two reads
int p = partition(pivot, records, left, right, leftValue, rightValue);
// Sort the two sub-lists recursively (p being the position of the partition)
Quicksort(records, left, p);
Quicksort(records, p+1, right);
}
/**
* Method to get the median pivot out of the leftmost, rightmost and middle element of an array
* @param left Leftmost index
* @param right Rightmost index
* @param records The Array to work on
* @param l The value of the array at the left index
* @param r The value of the array at the right index
* @return The value of the chosen median pivot
*/
private SortingItem getPivot(int left, int right, SortArray records, SortingItem l, SortingItem r) {
// Calculate the index of the middle element (rounded down)
int mIndex = (int) Math.floor(left + (right - left) / 2);
// If the array has only two items, the left item is the middle item so we don't have to look it up again
SortingItem m = (mIndex == left) ? l : records.getElementAt(mIndex);
SortingItem t = null;
// 'Sort' the three elements by doing two swaps if necessary, then return the middle (= median) one
if(l.compareTo(m) > 0) {
// The median element is the middle element of the sorted three element list of left, middle and right
// 'Sort' the three elements by doing two swaps if necessary, then return the middle one
if(l.compareTo(m) > 0) { // (if l is larger than m, l and m need to be swapped)
t = l;
l = m;
m = t;
}
if(r.compareTo(m) < 0) {
if(r.compareTo(m) < 0) { // (if r is smaller than the new m, r and m need to be swapped)
t = r;
r = m;
m = t;
}
return m;
return m; // return the new m
}
}

View File

@ -4,6 +4,8 @@ package lab;
*
* This class represents one entry of the list that has to be sorted.
*
* Added Comparable interface to be able to, well, compare items
*
*/
public class SortingItem implements Comparable<SortingItem>{
@ -24,8 +26,11 @@ public class SortingItem implements Comparable<SortingItem>{
this.Status = otherItem.Status;
}
// Compares self to another SortingItem, returns 0 if equal value, -1 if self is smaller, 1 if self is larger
@Override
public int compareTo(SortingItem arg0) {
// If the BookSerialNumbers are equal, we return the result of the ReaderID comparison, otherwise comparing BookSerialNumbers is sufficient
// (string comparisons are lexicographical)
return this.BookSerialNumber.compareTo(arg0.BookSerialNumber) == 0 ? this.ReaderID.compareTo(arg0.ReaderID): this.BookSerialNumber.compareTo(arg0.BookSerialNumber);
}