/*
* Copyright 2001-2013 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package com.uwyn.rife.tools;
/**
* Generic class that implements the quicksort algorithm. Extending classes
* have to implement the abstract methods so that the sorting algorithm can
* perform the appropriate modifications to the extending class's
* datastructure.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.0
*/
public abstract class Sort
{
/**
* Starts the sorting of the provided datastructure.
*
* @param dataToSort An <code>Object</code> instance that points to the
* datastructure that has to be sorted. The extending class should know how
* to manipulate this particular datastructure.
* @param lastElementPosition An integer that specifies the position of the
* last element in the provided datastructure.
* @param ascending true of the data has to be sorted in an ascending
* fashion and false otherwise
* @since 1.0
*/
public final void sort(Object dataToSort, int lastElementPosition, boolean ascending)
{
if (null == dataToSort) throw new IllegalArgumentException("dataToSort can't be null");
if (lastElementPosition < 0) throw new IllegalArgumentException("lastElementPosition has to be bigger than 0.");
quickSort(dataToSort, 0, lastElementPosition, ascending);
}
/**
* This method contains the actual sorting algorithm.
*
* @param dataToSort An <code>Object</code> instance that points to the
* datastructure that has to be sorted.
* @param lo0 An integer indicating the bottom boundary of the range that
* will be sorted.
* @param hi0 An integer indicating the upper boundary of the range that
* will be sorted.
* @param ascending true of the data has to be sorted in an ascending
* fashion and false otherwise
* @since 1.0
*/
protected final void quickSort(Object dataToSort, int lo0, int hi0, boolean ascending)
{
int lo = lo0;
int hi = hi0;
if (hi0 > lo0)
{
Object mid_element = elementAt(dataToSort, (lo0 + hi0) / 2);
while (lo <= hi)
{
if (ascending)
{
while ((lo < hi0) &&
compare(elementAt(dataToSort, lo), mid_element) < 0)
{
lo++;
}
while ((hi > lo0) &&
compare(elementAt(dataToSort, hi), mid_element) > 0)
{
hi--;
}
}
else
{
while ((lo < hi0) &&
compare(elementAt(dataToSort, lo), mid_element) > 0)
{
lo++;
}
while ((hi > lo0) &&
compare(elementAt(dataToSort, hi), mid_element) < 0)
{
hi--;
}
}
if (lo <= hi)
{
swap(dataToSort, lo, hi);
lo++;
hi--;
}
}
if (lo0 < hi)
{
quickSort(dataToSort, lo0, hi, ascending);
}
if (lo < hi0)
{
quickSort(dataToSort, lo, hi0, ascending);
}
}
}
/**
* Swaps the position of two entries in the provided datastructure. This is
* an abstract method that needs to be implemented by every extending class.
*
* @param dataToSort An <code>Object</code> instance that points to the
* datastructure in which the entries have to be swapped.
* @param position1 An integer with the position of the first entry.
* @param position2 An integer with the position of the second entry.
* @since 1.0
*/
protected abstract void swap(Object dataToSort, int position1, int position2);
/**
* Retrieves an entry from a certain position within the specified
* datastructure.
*
* @param dataToSort An <code>Object</code> instance that points to the
* datastructure from where the entry has to be retrieved.
* @param position An integer with the position of the entry that has to be
* retrieved.
* @return An <code>Object</code> instace containing the entry at the
* specified position.
* @since 1.0
*/
protected abstract Object elementAt(Object dataToSort, int position);
/**
* Compares the entries, determining which one comes before the other.
*
* @param element1 An <code>Object</code> instance containing the first
* entry.
* @param element2 An <code>Object</code> instance containing the second
* entry.
* @return <code>0</code> if the two entries are equals; or
* <p/>
* an integer <code><0</code> if the first entry comes before the second
* one; or
* <p/>
* an integer <code>>0</code> if the first entry comes after the second
* one
* @since 1.0
*/
protected abstract int compare(Object element1, Object element2);
}