// L-12 MCS 572 Mon 6 Feb 2012 : part_qsort.c
// This program partitions the vector to sort and then sorts the parts.
// As pivot we pick the middle element in the vector.  Exploiting
// the uniformity of the random doubles generated from [0,1], 0.5
// as pivot in the partitioning will cut the vector on average always
// in two equal halves.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void random_numbers ( int n, double *v );
/* returns n random doubles in [0,1] */

void write_numbers ( double *v, int lower, int upper );
/* writes the numbers in v from lower to upper,
 * including upper */

void partition
 ( double *v, int lower, int upper, int *pivot );
/* precondition: upper - lower > 0
 * takes v[lower] as pivot and interchanges elements so that
 * v[i] <= v[pivot] for all i < pivot, and
 * v[i] > v[pivot] for all i > pivot,
 * where lower <= pivot <= upper. */

int compare ( const void *e1, const void *e2 );
/* compares two elements of any type, for use in qsort of stdlib,
 * returns -1 if e1 < e2, 0 if e1 == e2, +1 if e1 > e2.  */

int main ( int argc, char *argv[] )
{
   int n;
   if(argc > 1)
      n = atoi(argv[1]);
   else
   {
      printf("give n : ");
      scanf("%d",&n);
   }
   int vb = 1;
   if(argc > 2) vb = atoi(argv[2]);
   srand(time(NULL));
   double *v;
   v = (double*)calloc(n,sizeof(double));
   random_numbers(n,v);
   if(vb > 0)
   {
      printf("%d random numbers : \n",n);
      write_numbers(v,0,n-1);
   }
   double tmp = v[0];
   v[0] = v[n/2]; v[n/2] = tmp;

   int lower = 0;
   int upper = n-1;
   int pivot = 0;
   if(n > 1) partition(v,lower,upper,&pivot);
   printf("pivot = %d\n",pivot);
  
   printf("-> sorting the first half : "); 
   printf("%d numbers\n",pivot);
   if(vb > 0) write_numbers(v,0,pivot-1);
   if(pivot != 0)
      qsort((void*)v,(size_t)pivot,
            sizeof(double),compare);
   if(vb > 0) printf("the pivot :\n");
   if(vb > 0) write_numbers(v,pivot,pivot);
   printf("-> sorting the second half : ");
   printf("%d numbers\n",n - pivot - 1);
   if(vb > 0) write_numbers(v,pivot+1,n-1);
   if(pivot != n)
      qsort((void*)&v[pivot+1],(size_t)(n-pivot-1),
            sizeof(double),compare);
   if(vb > 0)
   {
      printf("the sorted numbers :\n");
      write_numbers(v,0,n-1);
   }
   return 0;
}

void random_numbers ( int n, double *v )
{
   int i;
   for(i=0; i<n; i++)
      v[i] = ((double) rand())/RAND_MAX;
}

void write_numbers ( double *v, int lower, int upper )
{
   int i;
   for(i=lower; i<=upper; i++)
      printf("%.15e\n",v[i]);
}

void partition
 ( double *v, int lower, int upper, int *pivot )
{
   double x = v[lower];
   int up = lower+1;   /* index will go up */
   int down = upper;   /* index will go down */
   while(up < down)
   {
      while((up < down) && (v[up] <= x)) up++;
      while((up < down) && (v[down] > x)) down--;
      if(up == down) break;
      double tmp = v[up];
      v[up] = v[down]; v[down] = tmp;
   }
   if(v[up] > x) up--;
   v[lower] = v[up]; v[up] = x;
   *pivot = up;
}

int compare ( const void *e1, const void *e2 )
{
   double *i1 = (double*)e1;
   double *i2 = (double*)e2;
   return ((*i1 < *i2) ? -1 : (*i1 > *i2) ? +1 : 0);
}

