textfiles/programming/russell.lst

364 lines
6.8 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
--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);
}