static char *SccsId = "@(#)qsort.c 4.4 (TU-Delft) 04/16/93";
/**********************************************************

Name/Version      : makegln/4.4

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Author            : N.P. van der Meijs
Creation date     : 15-Mar-1988
Modified by       :
Modification date :


	Delft University of Technology
	Department of Electrical Engineering
	Network Theory Section
	Mekelweg 4 - P.O.Box 5031
	2600 GA DELFT
	The Netherlands

	Phone : 015 - 786234

	COPYRIGHT (C) 1988. All rights reserved.
**********************************************************/
#include <stdio.h>
#include "dmincl.h"
#include "config.h"
#include "aux/aux.h"
#include "makegln.h"

extern double infoPartitionBalance;
extern int infoNumPartitions;

/* quicksort implementation based on R. Sedgewick
 * 1. Algorithms, Addison Wesley, ISBN 0-201-06672-6, 1983.
 * 2. The article 'Implementing Quicksort Programs',
 *    Communications of the ACM, Volume 21, Number 10, 1978,
 *    page 847-857. (Very good article.)
 *
 * Main modification: randomization (see below).
 */

#define push(i) stack[p++] = i
#define pop(i)  i = stack[--p]
#define swap(a,b) {_swap_ = a; a = b; b = _swap_;}

sortBlock (base, N)
_edge_t ** base;
int N;
{
    int l = 0;                 /* left bound */
    int r = N - 1;             /* right bound */
    int p = 2;                 /* stack pointer */
    int i;
    int stack[50];                      /* stack */

    do {
	if (r - l > 15) {
	    /* Partition such that everyting to the left of i
	     * is smaller and to the right of i is larger
	     * than base[i]
	     */
	    i = partition (base, l, r);

            infoPartitionBalance += (double) (i - l) / (r - l);
	    infoNumPartitions++;

	    /* Now, push the largest subfile on the stack
	     * and continue (tail recursion removed)
	     * with the smallest subfile.
	     */
	    if ((i - l) > (r - i)) {
		push (l);
		push (i - 1);
		l = i + 1;
	    }
	    else {
		push (i + 1);
		push (r);
		r = i - 1;
	    }
	}
	else {
	    pop (r);
	    pop (l);
	}
    } while (p > 0);

    insertionsort (base, 0, N-1);
}


/*
 * We want a random int in the closed interval [l,r].
 * drand48 returns a random double in the semi-open [0,1).
 * Assignment of double to int is defined (Ansii C) to be
 * with truncation of the fraction bits.
 * Hence, adding 0.5 does the trick.
 */
extern double drand48 ();
# define RandomInt(l,r) \
    ((l) + ((int) ((drand48 () * ((r) - (l))) + 0.5)))

private partition (base, l, r)
_edge_t ** base;
int l, r;
{
    _edge_t ** U, **L, *T;
    _edge_t * v;
    int i, j;
    _edge_t * _swap_;

    /* Median of three partioning, see Sedgewick,
     * but with randomization (selection of median probes).
     * The need for this has been experimentally observed.
     * That is, there exist inputs that actually interfere
     * with the plain <l+1, r, (l+r)/2> median probes
     * in such a way that the partitioning process becomes
     * severely unbalanced.
     */

    i = RandomInt (l, r);
    swap (base[i], base[l]);

    i = RandomInt (l+1, r);
    swap (base[i], base[l+1]);

    i = RandomInt (l+2, r);
    swap (base[i], base[r]);

    /* Now we have random elements in l, l+1 and r.
     * Sort them so that l+1 <= l <= r
     * The elements in l+1 and r serve as sentinels
     * in the inner loop.
     */

    if (larger (base[l+1], base[r]))
	swap (base[l+1], base[r]);
    if (larger (base[l],   base[r]))
	swap (base[l],   base[r]);
    if (larger (base[l+1], base[l]))
	swap (base[l+1], base[l]);

#   ifdef DEBUG
    ASSERT (!larger  (base[l+1], base[l]));
    ASSERT (!smaller (base[r],   base[l]));
#   endif /* DEBUG */

    v = base[l];

    /* Pointer based loop.
     * On HP9000/800, does not make much difference when optimizer is used.
     * Should probably write everything with pointers.
     */
    L = base + l + 1;
    U = base + r;
    for (;;) {
	do {
	    L++;
	} while (smaller (*L, v));
	do {
	    U--;
	} while (larger  (*U, v));
	if (U < L)
	    break;
	T = *U; *U = *L; *L = T;        /* swap elements */
    }
    j = U - base;
    swap (base[l], base[j]);

#   ifdef POST
    /* post: a[l...j-1] <= a[j] <= a[j+1...r] */
    for (i = l;     i < j; i++) ASSERT (!larger  (base[i], base[j]));
    for (i = j+ 1; i <= r; i++) ASSERT (!smaller (base[i], base[j]));
#   endif POST

    return (j);
}

private insertionsort (base, L, U)
_edge_t ** base;
int L, U;
{
    _edge_t * v;
    int i, j;
    for (i = L + 1; i <= U; i++) {
       v = base[i]; j = i;
       while (larger (base[j - 1], v)) {
	   base[j] = base[j-1];
	   if (--j <= L)
	       break;
       }
       base[j] = v;
    }
}
