/*
  File name: fsort.c
  Created by: Ljubomir Buturovic
  Created: 05/02/2002
  Purpose: floating-point sorting functions based on code by
  R. Sedgewick.
*/

#include <float.h>
#include <stdlib.h>
#include "pcp.h"
#include "lau.h"
#include "sort.h"

static char rcsid[] = "$Id: fsort.c,v 1.12 2005/06/25 08:35:00 ljubomir Exp $";

/*
  In-place float sorting function based on algorithm by
  R. Sedgewick. In my experience, it is about 40% faster than the C
  library function qsort(). The sedgesort() function which implements
  the algorithm is downloaded from
  http://www.yendor.com/programming/sort/. ljb, 10/14/2001

  BIG NOTE: 'vector' needs to have len+1 elements, instead of the
  usual len. The first len elements are the numbers to be sorted. The
  last element is used internally by sedgesort() function (which is
  called by ssort()) as a 'sentinel'. This is obviously a restriction
  on part on finsort(); it means that the user must allocate one more
  element for each vector to be sorted. If this is not acceptable, use
  fsort(), which creates a new vector with the extra element.
*/
void finsort(float *vector, int len)
{
  if ((vector != (float *) 0) && (len > 0))
    {
      vector[len] = FLT_MAX;
      sedgesort(vector, len);
    }
}

/*
  Floating-point sorting function. The function allocates space for
  the sorted vector. The input 'vector' is not modifed.

  Return (float *) in case of error and set errno.
*/
float *fsort(float *vector, int len)
{
  float *vec;

  vec = malloc((len+1)*sizeof(float));
  if (vec != (float *) 0)
    {
      fvec_copy(vec, vector, len);
      finsort(vec, len);
    }
  return vec;
}

/*
  Floating-point sorting function. hsort() uses modified version of
  af_heapsort() to sort 'm' smallest values in a vector. This makes
  sense if 'k' is considerably smaller than the length of the vector;
  otherwise, sedgesort() is faster.
*/
void hsort(float *vector, int *len, int *m)
{
  int i;
  int length;
  int n;
  int limit;
  float temp;

  length = *len;
  n = *m;
  for (i = 0; i < length; i++)
    vector[i] = -vector[i];
  af_heapsort(vector, length, n);
  limit = length/2;
  if (n < limit)
    limit = n;
  for (i = 0; i < limit; i++)
    {
      temp = vector[i];
      vector[i] = vector[length-1-i];
      vector[length-1-i] = temp;
    }
  for (i = 0; i < n; i++)
    vector[i] = -vector[i];
}

/*
 |  void  af_heapsort (array, len)
 |  KEY_T  array[];
 |  int    len;
 |
 |  Abstract:	Sort array[0..len-1] into increasing order.
 |
 |  Method:	Heap-sort (ala Jon Bentley)
 |
 |  Advantages:
 |
 |	1. Stable sorting method (doesn't spoil relative order between
 |	   equal-key elements)
 |	2. Worst case complexity is O (n log(n))
 |	3. Method of choice when only the smallest n elemens are wanted
 |	   and not a full ordering (use sift n times).
 */

void  af_heapsort (KEY_T array[], int len, int n)
{
    register int	i;
    register KEY_T	temp, *sa = array - 1;
    int limit;
    /*
     |  'sa[]' is 'array[]' "shifted" one position to the left
     |  i.e.  sa[i] == array[i - 1]  (in particular:   sa[1] == array[0])
     |  'sa' has "Pascalish" indices and is thus more convenient
     |  for heap-sorting. An index i obeys the law:
     |	left_child (i) == 2i,  right_child (i) == 2i + 1
     |  Note: we don't use a[-1] which is outside our range, we just
     |  fake an array that starts one address lower, so we can refer
     |  to its first element as a[1] (rather than as a[0])
     */

    /* first step: make 'sa[]' a heap using siftdown len/2 times */
    for (i = len / 2; i >= 1; i--)
	siftdown (sa, i, len);

    /* heapify n times, to reach partial order */
    limit = 2;
    if (len-n+1 > 2)
      limit = len-n+1;
    for (i = len; i >= limit; i--) 
      {
	SWAP(sa[1], sa[i]);
	siftdown (sa, 1, i - 1);
      }
}


/*
 |  void  siftdown (array, lower, upper)
 |  KEY_T  array[];
 |  int    lower, upper;
 |
 |  Abstract:
 |	Assume array[] is a heap except array[lower] is not in order.
 |	Sift array[lower] down the heap as long as it is bigger than
 |	its two children nodes. Preserving the heap condition.
 |
 |	Optimization: rather than swapping array[i] with the greater
 |	of its children within the loop, we save array[lower]
 |	before the loop, shift the inner values within the loop, and
 |	finally plug the saved value into its final location.
 */
void  siftdown (KEY_T array[], int lower, int upper)
{
    register int	i = lower, c = lower;
    register int	lastindex = upper/2;
    register KEY_T	temp;

    temp = array[i];
    while (c <= lastindex) {
	c = 2 * i;		/* c = 2i is the left-child of i */
	if (c + 1 <= upper  &&  GT(array[c + 1], array[c]))
	    c++;		/* c is the greatest child of i */
	if (GE(temp, array[c])) break;
	array[i] = array[c];
	i = c;
    }
    array[i] = temp;
}



syntax highlighted by Code2HTML, v. 0.9.1