/*
quicksort and select as taken from CLR.  -bds 9/95
*/

#include "sort.h" 
/* sort.h defines
types Key, Record, Entry = struct{Key key, Record r},
and procedure swap.
and comparison operators on type Key  (>, <=, <, >=, ==, !=).
*/

Entry Slick_Select(Entry* A, int p, int r, int i);

int Slick_Partition(Entry* A, int p, int r) /*
Assumes p <= r are valid indices for A.
Returns index q, p <= q < r and permutes A so that 
A[p] thru A[q] are <= x and 
A[q+1] thru A[r] are >= x. 
where x is A[i] and p <= i <= r.
It is guaranteed that partition is relatively even, to be precise, 
for large n = r - p + 1, 
the sizes q - p + 1  and r - q + 1 of the two partitions 
are both >= 3n/10 - 3.
As a side effect, A is permuted (but not completely sorted).
*/{
  Entry* B;
  int n = r - p + 1;
  int k = n/5; // floor.
  B = malloc( (k+1)*sizeof(Entry) );/* could avoid using extra 
				       space like this */
  for (int i = 1, i <= k; i += 5) 
    {
    Anysort(A, i, i+4); 
    B[i] = A[i+2];
    }
  Entry x = Slick_Select(B, 1, k, k/2);
  return Partition(A, p, r, x.key);
  }

Entry Slick_Select(Entry* A, int p, int r, int i) /*
Assumes 1 <= i <= r - p + 1 and 
Returns the i-th smallest element of A[p] thru A[r], i.e. 
returns A'[i], where A' denotes what A would be if A[p] thru A[r] were 
sorted into increasing order.
As a side effect, A is permuted (but not completely sorted).
*/{
  if (p >= r) return A[p];
  else
    {
    int q = Slick_Partition(A, p, r), ;
    int k = q - p + 1; // k = size of lower partition.
    if (i <= k) 
      return Slick_Select(A, p, q, i);
    else
      return Slick_Select(A, q+1, r, i - k);
    }
  }
  
/* 
Theorem 1: Slick_Partition delivers on it's claim,
"the partition sizes are both >= 3n/10 - 4".
Proof summary:
Entries less than x are three in each of about half the groups of 5.

Theorem 2: for n = r - p + 1,
Slick_Select(A, p, q, i) and Slick_Partition(A, p, q, x)
both run in theta(n) time.

Proof summary: 
Let S(n) = time for Slick_Select and 
let P(n) = time for Slick_Partition.
Then by examining the code we see the recurrences:
S(n) <= P(n) + S(7n/10 + 4) + C, for some constant C 
P(n) = theta(n) + S(n/5).

Show by induction that S(n) <= D*n, if D >= 20*C and D >= S(1).

*/

void Slick_Quicksort(Entry* A, int p, int r)
/* 
Assumes p <= r are valid indices for A.
Permutes A so that A[p] thru A[r] are in increasing order.
*/{
  if (p < r) 
    {
    int q = Slick_Partition(A, p, r, A[p]);
    Slick_Quicksort(A, p, q);
    Slick_Quicksort(A, q+1, r);
    }


