www.pudn.com > geosteiner-3.1.zip > dsuf.c
/***********************************************************************
File: dsuf.c
Rev: a-1
Date: 11/03/98
Copyright (c) 1998, 2001 by David M. Warme
************************************************************************
The "disjoint set union-find" data structure.
************************************************************************
Modification Log:
a-1: 11/03/98 warme
: Created.
************************************************************************/
#include "dsuf.h"
#include "steiner.h"
/*
* Global Routines
*/
void dsuf_create (struct dsuf *, int);
int dsuf_find (struct dsuf *, int);
void dsuf_makeset (struct dsuf *, int);
void dsuf_unite (struct dsuf *, int, int);
/*
* Local Routines
*/
/* none */
/*
* This routine creates a collection of N disjoint sets. They are left
* uninitialized so that a sparse collection can be accessed quickly.
*/
void
dsuf_create (
struct dsuf * dsp, /* IN/OUT - sets to create */
int n /* IN - number of disjoint sets */
)
{
if (n <= 0) {
fatal ("dsuf_create: Bug 1.");
}
dsp -> set_size = n;
dsp -> parent = NEWA (n, int);
dsp -> rank = NEWA (n, int);
}
/*
* Destroy the given collection of disjoint sets.
*/
void
dsuf_destroy (
struct dsuf * dsp /* IN - sets to destroy */
)
{
free ((char *) (dsp -> rank));
free ((char *) (dsp -> parent));
dsp -> set_size = 0;
dsp -> parent = NULL;
dsp -> rank = NULL;
}
/*
* This routine makes a single disjoint set for item "i".
*/
void
dsuf_makeset (
struct dsuf * dsp, /* IN - collection of sets */
int i /* IN - item to make into a disjoint set */
)
{
if ((i < 0) OR (i >= dsp -> set_size)) {
/* Item out of bounds. */
fatal ("dsuf_makeset: Bug 1.");
}
dsp -> parent [i] = i;
dsp -> rank [i] = 0;
}
/*
* This routine "unites" two sets that were previously disjoint. I and J
* must be the "canonical" member of each disjoint set (i.e. they must
* each be the output of a "find" operation), and must be distinct.
*
* We perform the "union by rank" heuristic here.
*/
void
dsuf_unite (
struct dsuf * dsp, /* IN - collection of sets */
int i, /* IN - first set to unite */
int j /* IN - second set to unite */
)
{
int ri;
int rj;
if ((i < 0) OR (i >= dsp -> set_size)) {
/* Item I is out of range. */
fatal ("dsuf_unite: Bug 1.");
}
if ((j < 0) OR (j >= dsp -> set_size)) {
/* Item J is out of range. */
fatal ("dsuf_unite: Bug 2.");
}
if (i EQ j) {
/* Attempt to unite I with I. */
fatal ("dsuf_unite: Bug 3.");
}
ri = dsp -> rank [i];
rj = dsp -> rank [j];
if (ri EQ rj) {
/* Both subtrees have the same maximum depth. We */
/* arbitrarily choose I to be underneath J. The rank */
/* of J must then increase. */
dsp -> parent [i] = j;
dsp -> rank [j] = rj + 1;
}
else if (ri > rj) {
/* Tree I is (probably) deeper. Putting J underneath */
/* will not increase I's rank. */
dsp -> parent [j] = i;
}
else {
/* Tree J is (probably) deeper... */
dsp -> parent [i] = j;
}
}
/*
* This routine, given a member I of one of the disjoint sets A, will
* choose a cannonical member J of set A and return it. Until set A gets
* united with some other set, find (I) will always return the same J.
*
* This routine performs the "path compression" heuristic.
*/
int
dsuf_find (
struct dsuf * dsp, /* IN - collection of sets */
int i /* IN - item to find cannonical item for */
)
{
int j;
int k;
/* Yes, I know this routine is very elegent when coded */
/* recursively... Here's the iterative version. */
j = dsp -> parent [i];
if (i EQ j) {
/* A cannonical element has itself as parent. */
return (i);
}
/* We must search up the tree -- and compress when done... */
while (TRUE) {
k = dsp -> parent [j];
if (j EQ k) break;
j = k;
}
/* Now compress the path (make all items in chain point directly */
/* at the root K) -- we never have to do this search again! */
while (i NE k) {
j = dsp -> parent [i];
dsp -> parent [i] = k;
i = j;
}
return (k);
}