GENWiki

Premier IT Outsourcing and Support Services within the UK

User Tools

Site Tools


archive:programming:russell.lst

A GENERIC HEAPSORT ALGORITHM IN C by Stephen Russell

[LISTING ONE]

/* * The Heapsort to sort an array of n integers. */

static fixheap(h, i, n) int *h; unsigned i, n; {

unsigned k;
int	 tmp;
while ((k = 2 * i) <= n)		/* h[k] = left child of h[i] */
{
	/*  Find maximum of left and right children */
	if (k != n && h[k+1] > h[k])
		++k;			/* right child is greater */
	/* Compare greater of children to parent */
	if (h[i] >= h[k])
		return;
	/* Parent is less than child, so swap */
	tmp = h[k]; h[k] = h[i]; h[i] = tmp;
	i = k;				/* move down tree */
}

}

hsort(h, n) int *h; unsigned n; {

unsigned i;
int	 tmp;
  1. -h; /* adjust for zero-origin arrays in C */
for (i = n/2; i > 1; --i)
	fixheap(h, i, n);	/* build heap, except for h[1] */
while (n > 1)
{
	fixheap(h, 1, n);	/* move max to h[1] */
	tmp = h[1];		/* move max to final position */
	h[1] = h[n];
	h[n] = tmp;
	--n;			/* reduce size of heap */
}

}

[LISTING TWO]

/* * Generic Heapsort, derived from listing 1. */

#define H(k) (h + k * size)

static swap(p1, p2, n) /* swap n bytes */ char *p1, *p2; unsigned n; {

char	tmp;
while (n-- != 0)
{
	tmp = *p1; *p1++ = *p2; *p2++ = tmp;
}

}

static fixheap(h, size, cmp, i, n) char *h; unsigned size, i, n; int (*cmp)(); {

unsigned k;
while ((k = 2 * i) <= n)
{
	if (k != n && (*cmp)(H(k+1), H(k)) > 0)
		++k;
	if ((*cmp)(H(i), H(k)) >= 0)
		return;
	swap(H(i), H(k), size);
	i = k;
}

}

hsort(h, n, size, cmp) char *h; unsigned n, size; int (*cmp)(); {

unsigned i;
h -= size;
for (i = n/2; i > 1; --i)
	fixheap(h, size, cmp, i, n);
while (n > 1)
{
	fixheap(h, size, cmp, 1, n);
	swap(H(1), H(n), size);
	--n;
}

}

[LISTING THREE]

/* * Generic Heapsort. * * Synopsis: * hsort(char *base, unsigned n, unsigned size, int (*fn)()) * Description: * Hsort sorts the array of `n' items which starts at address `base'. * The size of each item is as given. Items are compared by the function * `fn', which is passed pointers to two items as arguments. The function * should return < 0 if item1 < item2, == 0 if item1 == item2, and > 0 * if item1 > item2. * Version: * 1988 April 28 * Author: * Stephen Russell, Department of Computer Science, * University of Sydney, 2006 * Australia. */

#ifdef INLINE

#define swap(p1, p2, n) {\

register char *_p1, *_p2;\
register unsigned _n;\
register char _tmp;\

\

for (_p1 = p1, _p2 = p2, _n = n; _n-- > 0; )\
{\
	_tmp = *_p1; *_p1++ = *_p2; *_p2++ = _tmp;\
}\

}\

#else

/* * Support routine for swapping elements of the array. */

static swap(p1, p2, n) register char *p1, *p2; register unsigned n; {

register char	ctmp;
/*
 *  On machines with no alignment restrictions for int's,
 *  the following loop may improve performance if moving lots
 *  of data. It has been commented out for portability.
 register int	itmp;
 for ( ; n > sizeof(int); n -= sizeof(int))
 {
	itmp = *(int *)p1;
	*(int *)p1 = *(int *)p2;
	p1 += sizeof(int);
	*(int *)p2 = itmp;
	p2 += sizeof(int);
}
  • /
while (n-- != 0)
{
	ctmp = *p1; *p1++ = *p2; *p2++ = ctmp;
}

}

#endif

/* * To avoid function calls in the inner loops, the code responsible for * constructing a heap from (part of) the array has been expanded inline. * It is possible to convert this common code to a function. The three * parameters base0, cmp and size are invariant - only the size of the * gap and the high bound of the array change. In phase 1, gap decreases * while hi is fixed. In phase 2, gap == size, and hi decreases. The * variables p, q, and g are only used in this common code. */

hsort(base, n, size, cmp) char *base; unsigned n; unsigned size; int (*cmp)(); {

register char	 *p, *q, *base0, *hi;
register unsigned gap, g;
if (n < 2)
	return;
base0 = base - size;		/* set up address of h[0] */
/*
 *  The gap is the distance, in bytes, between h[0] and h[i],
 *  for some i. It is also the distance between h[i] and h[2*i];
 *  that is, the distance between a node and its left child.
 *  The initial node of interest is h[n/2] (the rightmost
 *  interior node), so gap is set accordingly. The following is
 *  the only multiplication needed.
 */
gap = (n >> 1) * size; 		/* initial gap is n/2*size */
hi = base0 + gap + gap; 	/* calculate address of h[n] */
if (n & 1)
	hi += size;		/* watch out for odd arrays */
/*
 *  Phase 1: Construct heap from random data.
 *
 *  For i = n/2 downto 2, ensure h[i] is greater than its
 *  children h[2*i] and h[2*i+1]. By decreasing 'gap' at each
 *  iteration, we move down the heap towards h[2]. The final step
 *  of making h[1] the maximum value is done in the next phase.
 */
for ( ; gap != size; gap -= size)
{
	/*  fixheap(base0, size, cmp, gap, hi) */
	for (p = base0 + (g = gap); (q = p + g) <= hi; p = q)
	{
		g += g;		/* double gap for next level */
		/*
		 *  Find greater of left and right children.
		 */
		if (q != hi && (*cmp)(q + size, q) > 0)
		{
			q += size;	/* choose right child */
			g += size;	/* follow right subtree */
		}
		/*
		 *  Compare with parent.
		 */
		if ((*cmp)(p, q) >= 0)
			break;		/* order is correct */

		swap(p, q, size);	/* swap parent and child */
	}
}
/*
 *  Phase 2: Each iteration makes the first item in the
 *  array the maximum, then swaps it with the last item, which
 *  is its correct position. The size of the heap is decreased
 *  each iteration. The gap is always "size", as we are interested
 *  in the heap starting at h[1].
 */
for ( ; hi != base; hi -= size)
{
	/* fixheap(base0, size, cmp, gap (== size), hi) */
	p = base;		/* == base0 + size */
	for (g = size; (q = p + g) <= hi; p = q)
	{
		g += g;
		if (q != hi && (*cmp)(q + size, q) > 0)
		{
			q += size;
			g += size;
		}
		if ((*cmp)(p, q) >= 0)
			break;

		swap(p, q, size);
	}
	swap(base, hi, size);		/* move largest item to end */
}

}

[LISTING FOUR]

/* * Use hsort() to sort an array of strings read from input. */

#include <stdio.h>

#define MAXN 500 #define MAXSTR 1000

cmp(p1, p2) char p1, p2; {

return strcmp(*p1, *p2);

}

static char *string[MAXN]; static char buf[MAXSTR];

extern char *gets(); extern char *malloc();

main() {

char	*p;
int	i, n;
for (n = 0; gets(buf); ++n)
{
	if (n == MAXN)
	{
		fprintf(stderr, "Too many strings\n");
		exit(1);
	}
	p = malloc(strlen(buf) + 1);
	if (p == (char *)NULL)
	{
		fprintf(stderr, "Out of memory\n");
		exit(2);
	}
	strcpy(string[n] = p, buf);
}
hsort(string, n, sizeof string[0], cmp);
for (i = 0; i < n; ++i)
	puts(string[i]);
exit(0);

} 

/data/webs/external/dokuwiki/data/pages/archive/programming/russell.lst.txt · Last modified: 2001/11/08 10:27 by 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki