/*	sorting.c
	Implementations of primary sorting algorithms 

	by: Steven Skiena
	begun: February 5, 2002

*/


/*
Copyright 2003 by Steven S. Skiena; all rights reserved. 

Permission is granted for use in non-commerical applications
provided this copyright notice remains intact and unchanged.

This program appears in my book:

"Programming Challenges: The Programming Contest Training Manual"
by Steven Skiena and Miguel Revilla, Springer-Verlag, New York 2003.

See our website www.programming-challenges.com for additional information.

This book can be ordered from Amazon.com at

http://www.amazon.com/exec/obidos/ASIN/0387001638/thealgorithmrepo/

*/


#include <stdio.h>
#include "bool.h"
#include <math.h>
#include <stdlib.h>
#include "priority_queue.h"

#define NELEM	100		/* size of test arrays */

#define LESS_THAN	-1
#define EQUAL_TO	0
#define GREATER_THAN	1

bool compare(item_type a, item_type b)
{
	if (a < b) return(LESS_THAN);
	if (a > b) return(GREATER_THAN);
	return(EQUAL_TO);
}

/*	Swap the ith and jth elements of array s.	*/

newswap(item_type s[], int i, int j)
{
	item_type tmp;		/* placeholder */

	tmp = s[i];
	s[i] = s[j];
	s[j] = tmp;
}

insertion_sort(item_type s[], int n)
{
	int i,j;		/* counters */

	for (i=1; i<n; i++) {
		j=i;
		while ((j>0) && (s[j] < s[j-1])) {
			swap(&s[j],&s[j-1]);
			j = j-1;
		}
	}
}


selection_sort(item_type s[], int n)
{
        int i,j;                /* counters */
	int min;		/* index of minimum */

        for (i=0; i<n; i++) {
                min=i;
		for (j=i+1; j<n; j++) 
			if (s[j] < s[min]) min=j;
		swap(&s[i],&s[min]);
        }
}

/*	quicksort array s from the index l to index h.	*/

quicksort(item_type s[], int l, int h)
{
	int p;			/* index of partition */

	if ((h-l)>0) {
		p = partition(s,l,h);
		quicksort(s,l,p-1);
		quicksort(s,p+1,h);
	}
}

int partition(item_type s[], int l, int h)
{
	int i;			/* counter */
	int p;			/* pivot element index */
	int firsthigh;		/* divider position for pivot element */

	p = h;
	firsthigh = l;
	for (i=l; i<h; i++) 
		if (s[i] < s[p]) {
			swap(&s[i],&s[firsthigh]);
			firsthigh ++;
		}
	swap(&s[p],&s[firsthigh]);

	return(firsthigh);
}


heapsort(item_type s[], int n)
{
        int i;			/* counters */
	priority_queue q;	/* heap for heapsort */

	make_heap(&q,s,n);

	for (i=0; i<n; i++)
		s[i] = extract_min(&q);
}


mergesort(item_type s[], int n)
{
	int temp[NELEM+1];	/* copy items to create buffer for merging */
	int i;			/* counters */
	int top1, top2;		/* top element of each sorted half */
	int cnt1, cnt2;		/* number of elements left in each sorted half */

	for (i=0; i<n; i++) temp[i] = s[i];

	top1 = 0;
	cnt1 = n/2;
	mergesort(&(temp[top1]), cnt1);

	top2 = n/2;
	cnt2 = n - (n/2);
	mergesort(&(temp[top2]), cnt2);

	merge(s, &(temp[top1]), cnt1, &(temp[top2]), cnt2);
}

merge(item_type out[], item_type *in1, int cnt1, item_type *in2, int cnt2)
{
	bool take_from_1;	/* which side has the next element? */

	if ((cnt1 == 0) && (cnt2 == 0)) return;
	
	if (cnt1 == 0)
		take_from_1 = TRUE;			
	else if (cnt2 == 0)
		take_from_1 = FALSE;
	else if (compare(in1[0], in2[0]) == LESS_THAN) 
		take_from_1 = TRUE;
	else
		take_from_1 = FALSE;

	if (take_from_1) {
		out[0] = in1[0];
		merge(out[1],&(in1[1]),cnt1-1,in2,cnt2);
	}
	else {
		merge(out[1],in1,cnt1,&(in2[1]),cnt2-1);

	}
}

main()
{
	int s[NELEM+2];
	int n;
	int i,j;			/* counters */

	for (i=0; i<NELEM; i++) s[i] = NELEM-i;
	random_permutation(s,NELEM);

	insertion_sort(s,NELEM);

        printf("\n\nInsertion sort: \n");
        for (i=0; i<NELEM; i++) printf("%d ",s[i]);

        for (i=0; i<NELEM; i++) s[i] = NELEM-i;
        random_permutation(s,NELEM);

	selection_sort(s,NELEM);

	printf("\n\nSelection sort: \n");
        for (i=0; i<NELEM; i++) printf("%d ",s[i]);

        for (i=0; i<NELEM; i++) s[i] = NELEM-i;
        random_permutation(s,NELEM);

	quicksort(s,0,NELEM-1);

	printf("\n\nQuicksort: \n");
	for (i=0; i<NELEM; i++) printf("%d ",s[i]);

	for (i=0; i<NELEM; i++) s[i] = NELEM-i;
        random_permutation(s,NELEM);

	heapsort(s,NELEM);

	printf("\n\nHeapsort sort: \n");
	for (i=0; i<NELEM; i++) printf("%d ",s[i]);

        for (i=0; i<NELEM; i++) s[i] = NELEM-i;
        random_permutation(s,NELEM);

/*
        mergesort(s,NELEM);
*/
        printf("\n\nMergesort: \n");
        for (i=0; i<NELEM; i++) printf("%d ",s[i]);

        printf("\n");
}

