#include "heapsort.h"

/******************* Subroutines local to heapsort.c ************************/

static void add_to_sort_heap(int *heap,
			     float *sort_values,
			     int index,
			     int heap_tail);

static int get_top_of_heap_index(int *heap,
				 float *sort_values,
				 int heap_tail,
				 int start_index);


/********************* Subroutine definitions *******************************/


void
heapsort(int *sort_index,
	 float *sort_values,
	 int nelem,
	 int start_index)
{

/* This routine loads sort_index [1..nelem] with nelem values:  the indices  *
 * of the sort_values [1..nelem] array that lead to sort_values[index] being *
 * decreasing as one goes through sort_index.  Sort_values is not changed.   */

    int i;

	sort_index-=start_index;
	sort_values-=start_index;

/* Build a heap with the *smallest* element at the top. */

    for(i = 1; i <= nelem; i++)
	add_to_sort_heap(sort_index, sort_values, i, i);

/* Now pull items off the heap, smallest first.  As the heap (in sort_index) *
 * shrinks, I store the item pulled off (the smallest) in sort_index,        *
 * starting from the end. The heap and the stored smallest values never      *
 * overlap, so I get a nice sort-in-place.                                   */

    for(i = nelem; i >= 1; i--)
	sort_index[i] = get_top_of_heap_index(sort_index, sort_values, i, start_index);

	sort_index+=start_index;
	sort_values+=start_index;
}


static void
add_to_sort_heap(int *heap,
		 float *sort_values,
		 int index,
		 int heap_tail)
{

/* Adds element index, with value = sort_values[index] to the heap.          *
 * Heap_tail is the number of elements in the heap *after* the insert.       */

    unsigned int ifrom, ito;	/* Making these unsigned helps compiler opts. */
    int temp;

    heap[heap_tail] = index;
    ifrom = heap_tail;
    ito = ifrom / 2;

    while(ito >= 1 && sort_values[heap[ifrom]] < sort_values[heap[ito]])
	{
	    temp = heap[ito];
	    heap[ito] = heap[ifrom];
	    heap[ifrom] = temp;
	    ifrom = ito;
	    ito = ifrom / 2;
	}
}


static int
get_top_of_heap_index(int *heap,
		      float *sort_values,
		      int heap_tail,
			  int start_index)
{

/* Returns the index of the item at the top of the heap (the smallest one).  *
 * It then rebuilds the heap.  Heap_tail is the number of items on the heap  *
 * before the top item is deleted.                                           */

    int index_of_smallest, temp;
    unsigned int ifrom, ito, heap_end;

    index_of_smallest = heap[1];
    heap[1] = heap[heap_tail];
    heap_end = heap_tail - 1;	/* One item deleted. */
    ifrom = 1;
    ito = 2 * ifrom;

    while(ito <= heap_end)
	{
	    if(sort_values[heap[ito + 1]] < sort_values[heap[ito]])
		ito++;

	    if(sort_values[heap[ito]] > sort_values[heap[ifrom]])
		break;

	    temp = heap[ito];
	    heap[ito] = heap[ifrom];
	    heap[ifrom] = temp;
	    ifrom = ito;
	    ito = 2 * ifrom;
	}
	
	/*index must have the start_index subracted to be consistent with the original array*/
    return (index_of_smallest - start_index);
}
