mirror of https://github.com/YosysHQ/abc.git
622 lines
13 KiB
C
622 lines
13 KiB
C
/*
|
|
* Revision Control Information
|
|
*
|
|
* $Source: /vol/opua/opua2/sis/sis-1.2/common/src/sis/avl/RCS/avl.c,v $
|
|
* $Author: sis $
|
|
* $Revision: 1.3 $
|
|
* $Date: 1994/07/15 23:00:40 $
|
|
*
|
|
*/
|
|
/* LINTLIBRARY */
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "avl.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
|
|
|
|
#define HEIGHT(node) (node == NIL(avl_node) ? -1 : (node)->height)
|
|
#define BALANCE(node) (HEIGHT((node)->right) - HEIGHT((node)->left))
|
|
|
|
#define compute_height(node) { \
|
|
int x=HEIGHT(node->left), y=HEIGHT(node->right); \
|
|
(node)->height = MAX(x,y) + 1; \
|
|
}
|
|
|
|
#define COMPARE(key, nodekey, compare) \
|
|
((compare == avl_numcmp) ? \
|
|
(int) key - (int) nodekey : \
|
|
(*compare)(key, nodekey))
|
|
|
|
|
|
#define STACK_SIZE 50
|
|
|
|
static avl_node *new_node ();
|
|
static avl_node *find_rightmost ();
|
|
static void do_rebalance ();
|
|
static rotate_left ();
|
|
static rotate_right ();
|
|
static int do_check_tree ();
|
|
|
|
avl_tree *
|
|
avl_init_table (compar)
|
|
int (*compar) ();
|
|
{
|
|
avl_tree *tree;
|
|
|
|
tree = ALLOC (avl_tree, 1);
|
|
tree->root = NIL (avl_node);
|
|
tree->compar = compar;
|
|
tree->num_entries = 0;
|
|
return tree;
|
|
}
|
|
|
|
|
|
|
|
avl_lookup (tree, key, value_p)
|
|
avl_tree *tree;
|
|
register char *key;
|
|
char **value_p;
|
|
{
|
|
register avl_node *node;
|
|
register int (*compare) () = tree->compar, diff;
|
|
|
|
node = tree->root;
|
|
while (node != NIL (avl_node))
|
|
{
|
|
diff = COMPARE (key, node->key, compare);
|
|
if (diff == 0)
|
|
{
|
|
/* got a match */
|
|
if (value_p != NIL (char *))
|
|
*value_p = node->value;
|
|
return 1;
|
|
}
|
|
node = (diff < 0) ? node->left : node->right;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
avl_first (tree, key_p, value_p)
|
|
avl_tree *tree;
|
|
char **key_p;
|
|
char **value_p;
|
|
{
|
|
register avl_node *node;
|
|
|
|
if (tree->root == 0)
|
|
{
|
|
return 0; /* no entries */
|
|
}
|
|
else
|
|
{
|
|
/* walk down the tree; stop at leftmost leaf */
|
|
for (node = tree->root; node->left != 0; node = node->left)
|
|
{
|
|
}
|
|
if (key_p != NIL (char *))
|
|
*key_p = node->key;
|
|
if (value_p != NIL (char *))
|
|
*value_p = node->value;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
avl_last (tree, key_p, value_p)
|
|
avl_tree *tree;
|
|
char **key_p;
|
|
char **value_p;
|
|
{
|
|
register avl_node *node;
|
|
|
|
if (tree->root == 0)
|
|
{
|
|
return 0; /* no entries */
|
|
}
|
|
else
|
|
{
|
|
/* walk down the tree; stop at rightmost leaf */
|
|
for (node = tree->root; node->right != 0; node = node->right)
|
|
{
|
|
}
|
|
if (key_p != NIL (char *))
|
|
*key_p = node->key;
|
|
if (value_p != NIL (char *))
|
|
*value_p = node->value;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
avl_insert (tree, key, value)
|
|
avl_tree *tree;
|
|
char *key;
|
|
char *value;
|
|
{
|
|
register avl_node **node_p, *node;
|
|
register int stack_n = 0;
|
|
register int (*compare) () = tree->compar;
|
|
avl_node **stack_nodep[STACK_SIZE];
|
|
int diff, status;
|
|
|
|
node_p = &tree->root;
|
|
|
|
/* walk down the tree (saving the path); stop at insertion point */
|
|
status = 0;
|
|
while ((node = *node_p) != NIL (avl_node))
|
|
{
|
|
stack_nodep[stack_n++] = node_p;
|
|
diff = COMPARE (key, node->key, compare);
|
|
if (diff == 0)
|
|
status = 1;
|
|
node_p = (diff < 0) ? &node->left : &node->right;
|
|
}
|
|
|
|
/* insert the item and re-balance the tree */
|
|
*node_p = new_node (key, value);
|
|
do_rebalance (stack_nodep, stack_n);
|
|
tree->num_entries++;
|
|
tree->modified = 1;
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
avl_find_or_add (tree, key, slot_p)
|
|
avl_tree *tree;
|
|
char *key;
|
|
char ***slot_p;
|
|
{
|
|
register avl_node **node_p, *node;
|
|
register int stack_n = 0;
|
|
register int (*compare) () = tree->compar;
|
|
avl_node **stack_nodep[STACK_SIZE];
|
|
int diff;
|
|
|
|
node_p = &tree->root;
|
|
|
|
/* walk down the tree (saving the path); stop at insertion point */
|
|
while ((node = *node_p) != NIL (avl_node))
|
|
{
|
|
stack_nodep[stack_n++] = node_p;
|
|
diff = COMPARE (key, node->key, compare);
|
|
if (diff == 0)
|
|
{
|
|
if (slot_p != 0)
|
|
*slot_p = &node->value;
|
|
return 1; /* found */
|
|
}
|
|
node_p = (diff < 0) ? &node->left : &node->right;
|
|
}
|
|
|
|
/* insert the item and re-balance the tree */
|
|
*node_p = new_node (key, NIL (char));
|
|
if (slot_p != 0)
|
|
*slot_p = &(*node_p)->value;
|
|
do_rebalance (stack_nodep, stack_n);
|
|
tree->num_entries++;
|
|
tree->modified = 1;
|
|
return 0; /* not already in tree */
|
|
}
|
|
|
|
avl_delete (tree, key_p, value_p)
|
|
avl_tree *tree;
|
|
char **key_p;
|
|
char **value_p;
|
|
{
|
|
register avl_node **node_p, *node, *rightmost;
|
|
register int stack_n = 0;
|
|
char *key = *key_p;
|
|
int (*compare) () = tree->compar, diff;
|
|
avl_node **stack_nodep[STACK_SIZE];
|
|
|
|
node_p = &tree->root;
|
|
|
|
/* Walk down the tree saving the path; return if not found */
|
|
while ((node = *node_p) != NIL (avl_node))
|
|
{
|
|
diff = COMPARE (key, node->key, compare);
|
|
if (diff == 0)
|
|
goto delete_item;
|
|
stack_nodep[stack_n++] = node_p;
|
|
node_p = (diff < 0) ? &node->left : &node->right;
|
|
}
|
|
return 0; /* not found */
|
|
|
|
/* prepare to delete node and replace it with rightmost of left tree */
|
|
delete_item:
|
|
*key_p = node->key;
|
|
if (value_p != 0)
|
|
*value_p = node->value;
|
|
if (node->left == NIL (avl_node))
|
|
{
|
|
*node_p = node->right;
|
|
}
|
|
else
|
|
{
|
|
rightmost = find_rightmost (&node->left);
|
|
rightmost->left = node->left;
|
|
rightmost->right = node->right;
|
|
rightmost->height = -2; /* mark bogus height for do_rebal */
|
|
*node_p = rightmost;
|
|
stack_nodep[stack_n++] = node_p;
|
|
}
|
|
FREE (node);
|
|
|
|
/* work our way back up, re-balancing the tree */
|
|
do_rebalance (stack_nodep, stack_n);
|
|
tree->num_entries--;
|
|
tree->modified = 1;
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
avl_record_gen_forward (node, gen)
|
|
avl_node *node;
|
|
avl_generator *gen;
|
|
{
|
|
if (node != NIL (avl_node))
|
|
{
|
|
avl_record_gen_forward (node->left, gen);
|
|
gen->nodelist[gen->count++] = node;
|
|
avl_record_gen_forward (node->right, gen);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
avl_record_gen_backward (node, gen)
|
|
avl_node *node;
|
|
avl_generator *gen;
|
|
{
|
|
if (node != NIL (avl_node))
|
|
{
|
|
avl_record_gen_backward (node->right, gen);
|
|
gen->nodelist[gen->count++] = node;
|
|
avl_record_gen_backward (node->left, gen);
|
|
}
|
|
}
|
|
|
|
|
|
avl_generator *
|
|
avl_init_gen (tree, dir)
|
|
avl_tree *tree;
|
|
int dir;
|
|
{
|
|
avl_generator *gen;
|
|
|
|
/* what a hack */
|
|
gen = ALLOC (avl_generator, 1);
|
|
gen->tree = tree;
|
|
gen->nodelist = ALLOC (avl_node *, avl_count (tree));
|
|
gen->count = 0;
|
|
if (dir == AVL_FORWARD)
|
|
{
|
|
avl_record_gen_forward (tree->root, gen);
|
|
}
|
|
else
|
|
{
|
|
avl_record_gen_backward (tree->root, gen);
|
|
}
|
|
gen->count = 0;
|
|
|
|
/* catch any attempt to modify the tree while we generate */
|
|
tree->modified = 0;
|
|
return gen;
|
|
}
|
|
|
|
|
|
avl_gen (gen, key_p, value_p)
|
|
avl_generator *gen;
|
|
char **key_p;
|
|
char **value_p;
|
|
{
|
|
avl_node *node;
|
|
|
|
if (gen->count == gen->tree->num_entries)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
node = gen->nodelist[gen->count++];
|
|
if (key_p != NIL (char *))
|
|
*key_p = node->key;
|
|
if (value_p != NIL (char *))
|
|
*value_p = node->value;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
avl_free_gen (gen)
|
|
avl_generator *gen;
|
|
{
|
|
FREE (gen->nodelist);
|
|
FREE (gen);
|
|
}
|
|
|
|
static avl_node *
|
|
find_rightmost (node_p)
|
|
register avl_node **node_p;
|
|
{
|
|
register avl_node *node;
|
|
register int stack_n = 0;
|
|
avl_node **stack_nodep[STACK_SIZE];
|
|
|
|
node = *node_p;
|
|
while (node->right != NIL (avl_node))
|
|
{
|
|
stack_nodep[stack_n++] = node_p;
|
|
node_p = &node->right;
|
|
node = *node_p;
|
|
}
|
|
*node_p = node->left;
|
|
|
|
do_rebalance (stack_nodep, stack_n);
|
|
return node;
|
|
}
|
|
|
|
|
|
static void
|
|
do_rebalance (stack_nodep, stack_n)
|
|
register avl_node ***stack_nodep;
|
|
register int stack_n;
|
|
{
|
|
register avl_node **node_p, *node;
|
|
register int hl, hr;
|
|
int height;
|
|
|
|
/* work our way back up, re-balancing the tree */
|
|
while (--stack_n >= 0)
|
|
{
|
|
node_p = stack_nodep[stack_n];
|
|
node = *node_p;
|
|
hl = HEIGHT (node->left); /* watch for NIL */
|
|
hr = HEIGHT (node->right); /* watch for NIL */
|
|
if ((hr - hl) < -1)
|
|
{
|
|
rotate_right (node_p);
|
|
}
|
|
else if ((hr - hl) > 1)
|
|
{
|
|
rotate_left (node_p);
|
|
}
|
|
else
|
|
{
|
|
height = MAX (hl, hr) + 1;
|
|
if (height == node->height)
|
|
break;
|
|
node->height = height;
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
rotate_left (node_p)
|
|
register avl_node **node_p;
|
|
{
|
|
register avl_node *old_root = *node_p, *new_root, *new_right;
|
|
|
|
if (BALANCE (old_root->right) >= 0)
|
|
{
|
|
*node_p = new_root = old_root->right;
|
|
old_root->right = new_root->left;
|
|
new_root->left = old_root;
|
|
}
|
|
else
|
|
{
|
|
new_right = old_root->right;
|
|
*node_p = new_root = new_right->left;
|
|
old_root->right = new_root->left;
|
|
new_right->left = new_root->right;
|
|
new_root->right = new_right;
|
|
new_root->left = old_root;
|
|
compute_height (new_right);
|
|
}
|
|
compute_height (old_root);
|
|
compute_height (new_root);
|
|
}
|
|
|
|
|
|
static
|
|
rotate_right (node_p)
|
|
avl_node **node_p;
|
|
{
|
|
register avl_node *old_root = *node_p, *new_root, *new_left;
|
|
|
|
if (BALANCE (old_root->left) <= 0)
|
|
{
|
|
*node_p = new_root = old_root->left;
|
|
old_root->left = new_root->right;
|
|
new_root->right = old_root;
|
|
}
|
|
else
|
|
{
|
|
new_left = old_root->left;
|
|
*node_p = new_root = new_left->right;
|
|
old_root->left = new_root->right;
|
|
new_left->right = new_root->left;
|
|
new_root->left = new_left;
|
|
new_root->right = old_root;
|
|
compute_height (new_left);
|
|
}
|
|
compute_height (old_root);
|
|
compute_height (new_root);
|
|
}
|
|
|
|
static void
|
|
avl_walk_forward (node, func)
|
|
avl_node *node;
|
|
void (*func) ();
|
|
{
|
|
if (node != NIL (avl_node))
|
|
{
|
|
avl_walk_forward (node->left, func);
|
|
(*func) (node->key, node->value);
|
|
avl_walk_forward (node->right, func);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
avl_walk_backward (node, func)
|
|
avl_node *node;
|
|
void (*func) ();
|
|
{
|
|
if (node != NIL (avl_node))
|
|
{
|
|
avl_walk_backward (node->right, func);
|
|
(*func) (node->key, node->value);
|
|
avl_walk_backward (node->left, func);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
avl_foreach (tree, func, direction)
|
|
avl_tree *tree;
|
|
void (*func) ();
|
|
int direction;
|
|
{
|
|
if (direction == AVL_FORWARD)
|
|
{
|
|
avl_walk_forward (tree->root, func);
|
|
}
|
|
else
|
|
{
|
|
avl_walk_backward (tree->root, func);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
free_entry (node, key_free, value_free)
|
|
avl_node *node;
|
|
void (*key_free) ();
|
|
void (*value_free) ();
|
|
{
|
|
if (node != NIL (avl_node))
|
|
{
|
|
free_entry (node->left, key_free, value_free);
|
|
free_entry (node->right, key_free, value_free);
|
|
if (key_free != 0)
|
|
(*key_free) (node->key);
|
|
if (value_free != 0)
|
|
(*value_free) (node->value);
|
|
FREE (node);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
avl_free_table (tree, key_free, value_free)
|
|
avl_tree *tree;
|
|
void (*key_free) ();
|
|
void (*value_free) ();
|
|
{
|
|
free_entry (tree->root, key_free, value_free);
|
|
FREE (tree);
|
|
}
|
|
|
|
|
|
int
|
|
avl_count (tree)
|
|
avl_tree *tree;
|
|
{
|
|
return tree->num_entries;
|
|
}
|
|
|
|
static avl_node *
|
|
new_node (key, value)
|
|
char *key;
|
|
char *value;
|
|
{
|
|
register avl_node *new;
|
|
|
|
new = ALLOC (avl_node, 1);
|
|
new->key = key;
|
|
new->value = value;
|
|
new->height = 0;
|
|
new->left = new->right = NIL (avl_node);
|
|
return new;
|
|
}
|
|
|
|
|
|
int
|
|
avl_numcmp (x, y)
|
|
char *x, *y;
|
|
{
|
|
return (int) x - (int) y;
|
|
}
|
|
|
|
int
|
|
avl_check_tree (tree)
|
|
avl_tree *tree;
|
|
{
|
|
int error = 0;
|
|
(void) do_check_tree (tree->root, tree->compar, &error);
|
|
return error;
|
|
}
|
|
|
|
|
|
static int
|
|
do_check_tree (node, compar, error)
|
|
avl_node *node;
|
|
int (*compar) ();
|
|
int *error;
|
|
{
|
|
int l_height, r_height, comp_height, bal;
|
|
|
|
if (node == NIL (avl_node))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
r_height = do_check_tree (node->right, compar, error);
|
|
l_height = do_check_tree (node->left, compar, error);
|
|
|
|
comp_height = MAX (l_height, r_height) + 1;
|
|
bal = r_height - l_height;
|
|
|
|
if (comp_height != node->height)
|
|
{
|
|
(void) printf ("Bad height for 0x%08x: computed=%d stored=%d\n",
|
|
node, comp_height, node->height);
|
|
++*error;
|
|
}
|
|
|
|
if (bal > 1 || bal < -1)
|
|
{
|
|
(void) printf ("Out of balance at node 0x%08x, balance = %d\n",
|
|
node, bal);
|
|
++*error;
|
|
}
|
|
|
|
if (node->left != NIL (avl_node) &&
|
|
(*compar) (node->left->key, node->key) > 0)
|
|
{
|
|
(void) printf ("Bad ordering between 0x%08x and 0x%08x",
|
|
node, node->left);
|
|
++*error;
|
|
}
|
|
|
|
if (node->right != NIL (avl_node) &&
|
|
(*compar) (node->key, node->right->key) > 0)
|
|
{
|
|
(void) printf ("Bad ordering between 0x%08x and 0x%08x",
|
|
node, node->right);
|
|
++*error;
|
|
}
|
|
|
|
return comp_height;
|
|
}
|
|
ABC_NAMESPACE_IMPL_END
|
|
|