/*A testing laboratory made seven measurements each of the concentration of lead
  in the water supplies of five different municipalities.  Because the testing
  equipment occasionally generated large outliers, the experimenters decided to
  compute the median of each separate series of measurements, and then to take
  the median of those medians as a final result.  We'll write a generalised
  function that takes the median of any array of objects.*/

static void scalar_swap(b, i, j)
void *b;
int i, j;
  {
  int *bb = (int *)b;
  register int temp;
  temp = bb[i];
  bb[i] = bb[j];
  bb[j] = temp;
  }

static void vector_swap(b, i, j)
void *b;
int i, j;
  {
  int **bb = (int **)b;
  register int *temp;
  temp = bb[i];
  bb[i] = bb[j];
  bb[j] = temp;
  }

static int scalar_LessThan(b, i, j)
void *b;
int i, j;
  {
  int *bb = (int *)b;
  return(bb[i] < bb[j]);
  }

static int vector_LessThan(b, i, j)
void *b;
int i, j;
  {
  int **bb = (int **)b;
  return(bb[i][0] < bb[j][0]); /*median is in the 0th elt.*/
  }

/*Find the median of an array b.  This is accomplished using a partial
  quicksort; thus the contents of b end up as a permutation of the original
  sequence.  The median is placed in b[0].*/
void median(b, len, less_than, swap)
void *b;
int len;
int (*less_than)(void*, int, int);
void (*swap)(void*, int, int);
  {
  register int h, k, m, n;
  m = 0;
  n = len-1;
  /*inv: m <= len/2 < n and b[m..n] is a permutation of the subsequence
    b[m..n] of sorted sequence b[0..len-1]*/
  do
    {
    h = m+1;
    k = n;
    /*inv: b[m+1..h-1] <= b[m] and b[k+1..n] > b[m]*/
    while(h <= k)
      {
      while((h <= k) && (*less_than)(b, h, m))
	h++;
      while((h <= k) && !(*less_than)(b, k, m))
	k--;
      if(h < k)
	(*swap)(b, h++, k--);
      } /*elihw*/
    /*k=h-1*/
    if(k==m)
      m++;
    else if(h==n+1)
      (*swap)(b, m, n--);
    else
      {
      (*swap)(b, m, k);
      if(k <= len/2)
	m=k;
      else
	n=k;
      } /*fi*/
    /*b[k] is now in sorted position*/
    } while(k != len/2);
  (*swap)(b, k, 0); /*move the median element to the beginning of the array*/
  }

int main()
  {
  static int data0[] = {  48,   32,   27,    0, 1000,  101,   54};
  static int data1[] = {  96,  112,  132,  116,    0,  966,   98};
  static int data2[] = {  57,   63,   55,   59,   60, 1166,   54};
  static int data3[] = {2004,  512,  449,  613,  558,  485,  498};
  static int data4[] = { 208,  222,  199, 1170,  207,  238,  212};
  static int *(data[]) = {data0, data1, data2, data3, data4};
  register int sample;
  for(sample = 0; sample != 5; sample++)
    {
    median(data[sample], 7, scalar_LessThan, scalar_swap);
    printf("median of sample %d is %d\n", sample, data[sample][0]);
    }
  median(data, 5, vector_LessThan, vector_swap);
  printf("grand median is %d\n", data[0][0]);
  return 0;
  }

/*SUPPOSE WE DECLARED A TWO-DIMENSIONAL ARRAY data[][7] = {{...},{...},....}.
  WOULD THIS SIMPLIFY THINGS?  COULD WE USE THE SAME CODE FOR IT AS WE DID FOR
  THE ARRAY OF POINTERS ABOVE?  WHY, OR WHY NOT?  THINK ABOUT HOW THE TWO
  VERSIONS OF THE ARRAY ARE REPRESENTED IN MEMORY, AND HOW MANY LEVELS OF
  POINTERS THE PROGRAM IS DEREFERENCING.*/
