#include "SortAlgorithm.h"
#include <algorithm>

/**
  * A bubble sort demonstration algorithm based on
  * SortAlgorithm.java, Thu Oct 27 10:32:35 1994
  *
  * @author James Gosling
  * @version     1.6, 31 Jan 1995
  */
void BubbleSort::sort(array& a) 
{ sort(a,0,a.size()); }

void BubbleSort::sort(array& a, int lo, int hi)
{
  bool flipped = false;

  for (int i = hi; --i>=lo; ) {
    for (int j = 0; j<i; j++)
	if (a[j] > a[j+1]) {
	  swap(a[j],a[j+1]);
	  flipped = true;
	}
    if (!flipped) return;
    else flipped = false;
  }
}

/**
 * A bi-directional bubble sort demonstration algorithm based on
 * SortAlgorithm.java, Thu Oct 27 10:32:35 1994
 *
 * @author James Gosling
 * @version     1.6f, 31 Jan 1995
 */
void BidirectionalBubbleSort::sort(array& a)
{
  bool flipped;
  int j;
  int limit = a.size();
  int st = -1;

  while (st < limit) {
    flipped = false;
    st++;
    limit--;
    for (j = st; j < limit; j++)
      if (a[j] > a[j + 1]) {
	swap(a[j],a[j+1]);
	flipped = true;
      }

    if (!flipped)  return;

    for (j = limit; --j >= st;)
      if (a[j] > a[j + 1]) {
	swap(a[j],a[j+1]);
	flipped = true;
      }

    if (!flipped) return;
  }
}
 
/** 
  * A selection sort demonstration algorithm based on
  * SortAlgorithm.java, Thu Oct 27 10:32:35 1994 
  *
  * @author Jason Harrison@cs.ubc.ca
  * @version 1.0, 23 Jun 1995
  *
  */ 
void SelectionSort::sort(array& a) 
{ 
  int min;

  for (int i = 0; i < a.size(); i++) { 
      min = i;
      // Find the smallest element in the unsorted list (coudl use STL)
      for (int j = i + 1; j < a.size(); j++) 
	 if (a[j] < a[min]) min = j;

      // Swap the smallest unsorted element into the end of the sorted list.
      swap(a[min],a[i]);
    }
}

/**
  * A shell sort demonstration algorithm based on
  * SortAlgorithm.java, Thu Oct 27 10:32:35 1994
  * Note: Invented by Donald Lewis Shell [CACM, July, 1959, pages 30-32]
  * @author Jason Harrison@cs.ubc.ca
  * @version 1.0, 23 Jun 1995
  * @version 1.1, 12 Apr 2000
  * -- fixed java.lang.ArrayIndexOutOfBoundsException
  * Joel Berry found this bug
  */ 
void ShellSort::sort(array& a) 
{ 
  int j, B, h = 1; 
  // find the largest h value possible 
  while ((h * 3 + 1) < a.size()) h = 3 * h + 1;
  while( h > 0 ) {
    for (int i = h - 1; i < a.size(); i++) { 
      B = a[i]; j = i;
      for( j = i; (j >= h) && (a[j-h] > B); j -= h)
	a[j] = a[j-h];
      a[j] = B;
    }
    h = h / 3; 
  }
}

/**
  * A heap sort demonstration algorithm
  * SortAlgorithm.java, Thu Oct 27 10:32:35 1994
  *
  * @author Jason Harrison@cs.ubc.ca 
  * @version 1.0, 23 Jun 1995
  */ 
void HeapSort::sort(array& a) 
{ 
  int N = a.size(); 
  for (int k = N/2; k > 0; k--) { 
    downheap(a, k, N); } 
  do {
    swap(a[0],a[N]);
    N--;
    downheap(a, 1, N); 
  } while (N > 1); 
} 

void HeapSort::downheap(array& a, int k, int N)
{ 
  int T = a[k - 1]; 
  while (k <= N/2) { 
    int j = k + k; 
    if ((j < N) && (a[j - 1] < a[j])) j++;
    if (T >= a[j - 1]) break;
    else {
      a[k - 1] = a[j - 1]; 
      k = j;
    } 
  }
  a[k - 1] = T;
}

/** 
  * An insertion sort demonstration algorithm based on
  * SortAlgorithm.java, Thu Oct 27 10:32:35 1994
  * 
  * @author Jason Harrison@cs.ubc.ca
  * @version 1.0, 23 Jun 1995
  * 
  */
void InsertionSort::sort(array& a) 
{ 
  int i,j,B;
  for (i = 1; i < a.size(); i++) {
    j = i; 
    B = a[i];
    while ((j > 0) && (a[j-1] > B)) a[j] = a[--j];
    a[j] = B;
  }
}

/**
  * A merge sort demonstration algorithm
  * SortAlgorithm.java, Thu Oct 27 10:32:35 1994
  *
  * @author Jason Harrison@cs.ubc.ca
  * @version 1.1, 12 Jan 1998
  *
  * changed to sort range [lo,hi) 
  */ 
void MergeSort::sort(array& a, int lo, int hi, array& scratch) 
{ 
  if (lo >= hi-1) return;

  int mid = (lo+hi) / 2;
  sort(a, lo, mid, scratch);      /* Sort sublist a[lo..mid]   */
  sort(a, mid, hi, scratch);    /* Sort sublist a[mid+1..hi] */

  merge(a.begin()+lo,a.begin()+mid,a.begin()+mid,a.begin()+hi,scratch.begin()+lo);
  swap_ranges(scratch.begin()+lo,scratch.begin()+hi,a.begin()+lo);
}

void MergeSort::sort(array& a) 
{ 
  array scratch(a.size());
  sort(a, 0, a.size(), scratch); 
}

/**
 * A quick sort demonstration algorithm based on
 * SortAlgorithm.java, Thu Oct 27 10:32:35 1994
 *
 * @author James Gosling
 * @version     1.6f, 31 Jan 1995
 *
 */
void QuickSort::sort(array& a, int lo, int hi) 
{
  // Base case
  if (lo >= hi) return;
  else if( lo == hi - 1 ) {
    if (a[lo] > a[hi]) swap(a[lo],a[hi]);
    return;
  }

  int mid = partition(a, lo, hi, pickPivot(a, lo, hi));

  sort(a, lo, mid-1);
  sort(a, mid+1, hi);
}

void QuickSort::sort(array& a)
{ sort(a, 0, a.size()-1); }

int QuickSort::partition(array& a, int lo, int hi0, int pivot)
{
  int hi = hi0;

  swap(a[pivot],a[hi0]);

  while( lo < hi ) {
    while (a[lo] <= a[hi0] && lo < hi) lo++;
    while (a[hi0] <= a[hi] && lo < hi) hi--;
    if( lo < hi ) swap(a[lo],a[hi]);
  }
  swap(a[hi0],a[hi]);
  return hi;
}

// return the index of the pivot value
int QuickSort::pickPivot(array& a, int lo, int hi)
{ return (lo + hi) / 2; }

void QubbleSort::sort(array& a, int lo, int hi, int spread) 
{
  if ((hi-lo) <= spread) {
    BubbleSort s;
    s.sort(a,lo,hi);
    return;
  }

  int mid = partition(a, lo, hi, pickPivot(a, lo, hi));

  sort(a, lo, mid-1, spread);
  sort(a, mid+1, hi, spread);
}

void QubbleSort::sort(array& a)
{ sort(a, 0, a.size()-1, 8); }

void FastQuickSort::sort(array& a, int lo, int hi, int spread)
{
  int pivot;

  if ((hi-lo)>spread)
    {
      pivot = pickPivot(a,hi,lo);
      if (a[lo]>a[pivot]) swap(a[lo],a[pivot]);
      if (a[lo]>a[hi]) swap(a[lo],a[hi]);
      if (a[pivot]>a[hi]) swap(a[pivot],a[hi]);
		
      int mid = partition(a,lo+1,hi-1,pivot);

      sort(a,lo,mid-1,spread);
      sort(a,mid+1,hi,spread);
    }
}

void FastQuickSort::sort(array& a)
{
  InsertionSort s;
  sort(a, 0, a.size() - 1,4);
  s.sort(a);
}

