mirror of
https://github.com/tu-darmstadt-informatik/AuD18.git
synced 2025-12-13 01:45:49 +00:00
Add lots of documentation
This commit is contained in:
parent
eec221506b
commit
c55a7ecb6d
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user