562 lines
14 KiB
C
562 lines
14 KiB
C
/*
|
|
* heap.c -
|
|
*
|
|
* Routines to create and manipulate heaps.
|
|
*
|
|
* *********************************************************************
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
* * software and its documentation for any purpose and without *
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
* * notice appear in all copies. The University of California *
|
|
* * makes no representations about the suitability of this *
|
|
* * software for any purpose. It is provided "as is" without *
|
|
* * express or implied warranty. Export of this software outside *
|
|
* * of the United States of America may require an export license. *
|
|
* *********************************************************************
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/utils/heap.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "utils/heap.h"
|
|
#include "utils/utils.h"
|
|
#include "utils/malloc.h"
|
|
|
|
/* C99 compat */
|
|
#include "textio/textio.h"
|
|
|
|
#define heapLeft(used,i) ((used) < ( (i)<<1) ? 0 : (i)+(i) )
|
|
#define heapRight(used,i) ((used) < (((i)<<1)+1) ? 0 : (i)+(i)+1)
|
|
|
|
#define KEY_LESS_COND(t, l, i1, i2, stmt) \
|
|
switch (t) { \
|
|
case HE_INT: if (l[i1].he_int < l[i2].he_int) stmt; \
|
|
break; \
|
|
case HE_DLONG: if ((l[i1].he_dlong < l[i2].he_dlong)) stmt; \
|
|
break; \
|
|
case HE_DOUBLE: if (l[i1].he_double < l[i2].he_double) stmt; \
|
|
break; \
|
|
case HE_FLOAT: if (l[i1].he_float < l[i2].he_float) stmt; \
|
|
break; \
|
|
}
|
|
|
|
#define KEY_LE_COND(t, l, i1, i2, stmt) \
|
|
switch (t) { \
|
|
case HE_INT: if (l[i1].he_int <= l[i2].he_int) stmt; \
|
|
break; \
|
|
case HE_DLONG: if ((l[i1].he_dlong <=l[i2].he_dlong)) stmt; \
|
|
break; \
|
|
case HE_DOUBLE: if (l[i1].he_double <= l[i2].he_double) stmt; \
|
|
break; \
|
|
case HE_FLOAT: if (l[i1].he_float <= l[i2].he_float) stmt; \
|
|
break; \
|
|
}
|
|
|
|
#define KEY_GREATER_COND(t, l, i1, i2, stmt) \
|
|
switch (t) { \
|
|
case HE_INT: if (l[i1].he_int > l[i2].he_int) stmt; \
|
|
break; \
|
|
case HE_DLONG:if(l[i1].he_dlong > l[i2].he_dlong) stmt; \
|
|
break; \
|
|
case HE_DOUBLE: if (l[i1].he_double > l[i2].he_double) stmt; \
|
|
break; \
|
|
case HE_FLOAT: if (l[i1].he_float > l[i2].he_float) stmt; \
|
|
break; \
|
|
}
|
|
|
|
#define KEY_GE_COND(t, l, i1, i2, stmt) \
|
|
switch (t) { \
|
|
case HE_INT: if (l[i1].he_int >= l[i2].he_int) stmt; \
|
|
break; \
|
|
case HE_DLONG: if ((l[i1].he_dlong >= l[i2].he_dlong)) stmt; \
|
|
break; \
|
|
case HE_DOUBLE: if (l[i1].he_double >= l[i2].he_double) stmt; \
|
|
break; \
|
|
case HE_FLOAT: if (l[i1].he_float >= l[i2].he_float) stmt; \
|
|
break; \
|
|
}
|
|
|
|
/* Forward declarations */
|
|
|
|
extern void heapify();
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* HeapInit --
|
|
* HeapInitType --
|
|
*
|
|
* Initialize a heap. The first form is a heap with integer keys; the
|
|
* second allows specification of the type of key to use.
|
|
*
|
|
* Note that with this addressing scheme it is necessary to allocate
|
|
* 2**n + 1 locations for the heap block, location 0 being unused.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Allocates storage for the heap. Initializes the fields in the heap
|
|
* struct. Memory is allocated.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
HeapInit(heap, size, descending, stringIds)
|
|
Heap *heap; /* Pointer to a heap struct */
|
|
int size; /* Initial size of heap */
|
|
int descending; /* TRUE if largest on top */
|
|
int stringIds; /* TRUE if entry id's are strings */
|
|
{
|
|
HeapInitType(heap, size, descending, stringIds, HE_INT);
|
|
}
|
|
|
|
void
|
|
HeapInitType(heap, size, descending, stringIds, keyType)
|
|
Heap *heap; /* Pointer to a heap struct */
|
|
int size; /* Initial size of heap */
|
|
int descending; /* TRUE if largest on top */
|
|
int stringIds; /* TRUE if entry id's are strings */
|
|
int keyType; /* Type of keys to use */
|
|
{
|
|
if (size < 0) size = -size;
|
|
heap->he_size = 2;
|
|
while (size > heap->he_size)
|
|
heap->he_size <<= 1;
|
|
heap->he_used = 0;
|
|
heap->he_built = 0;
|
|
heap->he_big = descending;
|
|
heap->he_stringId = stringIds;
|
|
|
|
/*
|
|
* Add 2 to the size because location 0 is used as a temporary,
|
|
* and location (2**n) + 1 is the last leaf
|
|
*/
|
|
switch (heap->he_keyType = keyType)
|
|
{
|
|
case HE_INT:
|
|
case HE_DLONG:
|
|
case HE_FLOAT:
|
|
case HE_DOUBLE:
|
|
break;
|
|
default:
|
|
TxError("Unsupported key type: %d\n", keyType);
|
|
break;
|
|
}
|
|
|
|
heap->he_list = (HeapEntry *) mallocMagic((unsigned) ((heap->he_size+2)
|
|
* sizeof (HeapEntry)));
|
|
ASSERT(heap->he_list != NULL, "Malloc failed in HeapInit");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* HeapKill --
|
|
*
|
|
* Deallocate all storage associated with the heap.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Storage is freed. Fields in the heap record are reset. If func is
|
|
* not NULL then call it with each heap element before freeing the heap
|
|
* entry.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
HeapKill(heap, func)
|
|
Heap *heap; /* The heap being killed */
|
|
void (*func)(); /* Some function to free each id element */
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
* Free used locations except 0, since that location is reserved to pass
|
|
* back values.
|
|
*/
|
|
if (func)
|
|
for (i = 1; i <= heap->he_used; i++)
|
|
(*func) (heap, i);
|
|
freeMagic((char *) heap->he_list);
|
|
heap->he_list = NULL;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* HeapFreeIdFunc --
|
|
*
|
|
* Supplied function to HeapKill. Frees the referenced entry id if it
|
|
* is a string, otherwise do nothing.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Memory is freed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
HeapFreeIdFunc(heap, i)
|
|
Heap *heap; /* The heap in which the free is performed */
|
|
int i; /* The index of the entry whose id gets freed */
|
|
{
|
|
if (heap->he_stringId)
|
|
freeMagic(heap->he_list[i].he_id);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* HeapRemoveTop --
|
|
* Delete the top element from the heap.
|
|
*
|
|
* Results:
|
|
* Pointer to the removed heap element, which is the same as the entry
|
|
* pointer passed to the function from outside, or NULL if no entries
|
|
* remain.
|
|
*
|
|
* Side effects:
|
|
* If the heap has been touched, restore the heap property before removing
|
|
* the top element.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
HeapEntry *
|
|
HeapRemoveTop(heap, entry)
|
|
Heap *heap; /* The heap from which the top is removed */
|
|
HeapEntry *entry; /* Return the value in this struct */
|
|
{
|
|
int i;
|
|
|
|
if (heap->he_used == 0)
|
|
return (HeapEntry *) NULL;
|
|
|
|
if (!heap->he_built)
|
|
for (i = heap->he_used; i > 0; i--)
|
|
heapify(heap, i);
|
|
|
|
heap->he_built = heap->he_used;
|
|
*entry = heap->he_list[1];
|
|
heap->he_list[1] = heap->he_list[heap->he_used];
|
|
heap->he_used--;
|
|
heapify(heap, 1);
|
|
return entry;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* HeapLookAtTop --
|
|
*
|
|
* Return pointer to top element, but don't remove it.
|
|
*
|
|
* Results:
|
|
* Pointer to the top heap element, or NULL if heap is empty.
|
|
*
|
|
* Side effects:
|
|
* If the heap has been touched, restore the heap property before
|
|
* returning the top element.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
HeapEntry *
|
|
HeapLookAtTop(heap)
|
|
Heap *heap;
|
|
{
|
|
int i;
|
|
|
|
if (heap->he_used == 0)
|
|
return (HeapEntry *) NULL;
|
|
|
|
if (!heap->he_built)
|
|
for (i = heap->he_used; i > 0; i--)
|
|
heapify(heap, i);
|
|
|
|
heap->he_built = heap->he_used;
|
|
return &heap->he_list[1];
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* heapify --
|
|
*
|
|
* Restore the heap property to the heap, where the root has changed.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Things get shuffled around in the heap. Location 0 is trashed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
heapify(heap, root)
|
|
Heap *heap;
|
|
int root;
|
|
{
|
|
HeapEntry *list = heap->he_list;
|
|
int x, r, used = heap->he_used;
|
|
int keyType = heap->he_keyType;
|
|
|
|
if (heap->he_big)
|
|
{
|
|
/* Biggest one on the top of the heap */
|
|
while (1)
|
|
{
|
|
if ((x = heapLeft(used, root)) == 0) break;
|
|
if ((r = heapRight(used, root)))
|
|
KEY_LESS_COND(keyType, list, x, r, x = r);
|
|
|
|
KEY_LE_COND(keyType, list, x, root, return);
|
|
*list = list[root];
|
|
list[root] = list[x];
|
|
list[x] = *list;
|
|
root = x;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Smallest one on the top of the heap */
|
|
while (1)
|
|
{
|
|
if ((x = heapLeft(used, root)) == 0) break;
|
|
if ((r = heapRight(used, root)))
|
|
KEY_GREATER_COND(keyType, list, x, r, x = r);
|
|
KEY_GE_COND(keyType, list, x, root, return);
|
|
*list = list[root];
|
|
list[root] = list[x];
|
|
list[x] = *list;
|
|
root = x;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* HeapAdd --
|
|
*
|
|
* Add an item to the bottom of the heap. Restore the heap structure
|
|
* by propagating the item upwards.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Things get shuffled around in the heap.
|
|
* Free the old block and allocate a larger block if necessary.
|
|
*
|
|
* Warning:
|
|
* Something awful may happen if the id value was declared a string in
|
|
* HeapInit and you provide something else.
|
|
*
|
|
* Note:
|
|
* Because throwing pointers to indeterminate types (int, float, etc.)
|
|
* into the second argument produces results with unititialized fields,
|
|
* use of HeapAdd() is now deprecated, in favor of the determinate-type
|
|
* versions HeapAddInt, etc. (see below). These routines also protect
|
|
* against writing any data type into a heap initialized as a different
|
|
* data type.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
HeapAdd(heap, pKey, id)
|
|
Heap *heap;
|
|
union heUnion *pKey;
|
|
char *id;
|
|
{
|
|
HeapEntry *list = heap->he_list;
|
|
int i, cmp, keyType;
|
|
|
|
keyType = heap->he_keyType;
|
|
if (heap->he_used == heap->he_size)
|
|
{
|
|
HeapEntry *new;
|
|
|
|
/* Need to recopy to a larger area */
|
|
new = (HeapEntry *) mallocMagic((unsigned) ((2 * heap->he_size + 2)
|
|
* sizeof (HeapEntry)));
|
|
bcopy((char *) list, (char *) new,
|
|
(heap->he_size + 2) * sizeof (HeapEntry));
|
|
freeMagic((char *) heap->he_list);
|
|
heap->he_list = list = new;
|
|
heap->he_size *= 2;
|
|
}
|
|
|
|
i = ++heap->he_used;
|
|
list[i].he_union = *pKey;
|
|
if (heap->he_stringId) list[i].he_id = StrDup((char **) NULL, id);
|
|
else list[i].he_id = id;
|
|
|
|
if (heap->he_built)
|
|
{
|
|
if (heap->he_big)
|
|
{
|
|
/* Biggest on the top */
|
|
while (1)
|
|
{
|
|
/* If odd then new entry is the right half of a pair */
|
|
cmp = i;
|
|
if ((i & 1) && (i != 1))
|
|
KEY_LE_COND(keyType, list, i, i-1, cmp = i-1);
|
|
|
|
/* Find parent. If 0 then at the root so quit */
|
|
if ((i >>= 1) == 0) return;
|
|
|
|
KEY_LE_COND(keyType, list, cmp, i, return);
|
|
list[0] = list[cmp]; list[cmp] = list[i]; list[i] = list[0];
|
|
heapify(heap, cmp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Smallest on top */
|
|
while (1)
|
|
{
|
|
/* If odd then new entry is the right half of a pair */
|
|
cmp = i;
|
|
if ((i & 1) && (i != 1))
|
|
KEY_GE_COND(keyType, list, i, i-1, cmp = i-1);
|
|
|
|
/* Find parent. If 0 then at the root so quit */
|
|
if ((i >>= 1) == 0) return;
|
|
|
|
KEY_GE_COND(keyType, list, cmp, i, return);
|
|
list[0] = list[cmp]; list[cmp] = list[i]; list[i] = list[0];
|
|
heapify(heap, cmp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* HeapAddInt, HeapAddDLong, HeapAddFloat, HeapAddDouble --
|
|
*
|
|
* Type-determinate versions of HeapAdd(). Note that unlike HeapAdd(),
|
|
* the second argument is the value, not a pointer to the value.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
HeapAddInt(heap, data, id)
|
|
Heap *heap;
|
|
int data;
|
|
char *id;
|
|
{
|
|
union heUnion pKey;
|
|
|
|
ASSERT(heap->he_keyType == HE_INT,
|
|
"Attempt to add type int to non-int heap.");
|
|
pKey.hu_int = data;
|
|
HeapAdd(heap, &pKey, id);
|
|
}
|
|
|
|
void
|
|
HeapAddDLong(heap, data, id)
|
|
Heap *heap;
|
|
dlong data;
|
|
char *id;
|
|
{
|
|
union heUnion pKey;
|
|
|
|
ASSERT(heap->he_keyType == HE_DLONG,
|
|
"Attempt to add type double long to non-double long heap.");
|
|
pKey.hu_dlong = data;
|
|
HeapAdd(heap, &pKey, id);
|
|
}
|
|
|
|
void
|
|
HeapAddFloat(heap, data, id)
|
|
Heap *heap;
|
|
float data;
|
|
char *id;
|
|
{
|
|
union heUnion pKey;
|
|
|
|
ASSERT(heap->he_keyType == HE_FLOAT,
|
|
"Attempt to add type float to non-float heap.");
|
|
pKey.hu_float = data;
|
|
HeapAdd(heap, &pKey, id);
|
|
}
|
|
|
|
void
|
|
HeapAddDouble(heap, data, id)
|
|
Heap *heap;
|
|
double data;
|
|
char *id;
|
|
{
|
|
union heUnion pKey;
|
|
|
|
ASSERT(heap->he_keyType == HE_DOUBLE,
|
|
"Attempt to add type double to non-double heap.");
|
|
pKey.hu_double = data;
|
|
HeapAdd(heap, &pKey, id);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* HeapDump --
|
|
* Dump the contents of the heap for debugging purposes.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
HeapDump(heap)
|
|
Heap *heap;
|
|
{
|
|
int i;
|
|
|
|
if (heap->he_big) printf("Heap with biggest on the top\n");
|
|
else printf("Heap with smallest on the top\n");
|
|
|
|
for (i = 1; i <= heap->he_used; i++)
|
|
{
|
|
printf("[%d]: Key ", i);
|
|
switch (heap->he_keyType)
|
|
{
|
|
case HE_INT: printf("%d", heap->he_list[i].he_int); break;
|
|
case HE_FLOAT: printf("%f", heap->he_list[i].he_float); break;
|
|
case HE_DOUBLE: printf("%f", heap->he_list[i].he_double); break;
|
|
case HE_DLONG: printf("%"DLONG_PREFIX"d", heap->he_list[i].he_dlong); break;
|
|
}
|
|
if (heap->he_stringId == TRUE)
|
|
printf("//id %s; ", heap->he_list[i].he_id);
|
|
else
|
|
printf("//id %p; ", heap->he_list[i].he_id);
|
|
}
|
|
printf("\n");
|
|
}
|