blob: c1e9e5584ce31454cbb574cf8f33f294a09d918d [file] [log] [blame]
#include <zebra.h>
#include "ospf6_bintree.h"
static struct bintree_node *
bintree_lookup_node_min (struct bintree_node *subroot)
{
struct bintree_node *node;
if (subroot == NULL)
return NULL;
node = subroot;
while (node->bl_left)
node = node->bl_left;
return node;
}
static struct bintree_node *
bintree_lookup_node_max (struct bintree_node *subroot)
{
struct bintree_node *node;
assert (subroot != NULL);
node = subroot;
while (node->bl_right)
node = node->bl_right;
return node;
}
void *
bintree_lookup (void *data, struct bintree *tree)
{
int cmp;
struct bintree_node *node;
node = tree->root;
while (node)
{
if (tree->cmp)
cmp = (*tree->cmp) (node->data, data);
else
cmp = (node->data - data);
if (cmp == 0)
break;
if (cmp > 0)
node = node->bl_left;
else /* if (cmp < 0) */
node = node->bl_right;
}
if (node)
return node->data;
return NULL;
}
void *
bintree_lookup_min (struct bintree *tree)
{
struct bintree_node *node;
node = bintree_lookup_node_min (tree->root);
if (node == NULL)
return NULL;
return node->data;
}
void *
bintree_lookup_max (struct bintree *tree)
{
struct bintree_node *node;
node = bintree_lookup_node_max (tree->root);
if (node == NULL)
return NULL;
return node->data;
}
int
bintree_add (void *data, struct bintree *tree)
{
int cmp = 0;
struct bintree_node *node, *parent;
node = tree->root;
parent = NULL;
while (node)
{
if (tree->cmp)
cmp = (*tree->cmp) (node->data, data);
else
cmp = (node->data - data);
if (cmp == 0)
break;
parent = node;
if (cmp > 0)
node = node->bl_left;
else /* if (cmp < 0) */
node = node->bl_right;
}
if (node)
return -1;
node = malloc (sizeof (struct bintree_node));
memset (node, 0, sizeof (struct bintree_node));
node->tree = tree;
node->data = data;
if (parent)
{
node->parent = parent;
assert (cmp != 0);
if (cmp > 0)
{
node->parent_link = BL_LEFT;
parent->bl_left = node;
}
else /* if (cmp < 0) */
{
node->parent_link = BL_RIGHT;
parent->bl_right = node;
}
}
else
tree->root = node;
tree->count++;
return 0;
}
static void
bintree_remove_nochild (struct bintree_node *node)
{
assert (node->bl_left == NULL && node->bl_right == NULL);
if (node->parent == NULL)
node->tree->root = NULL;
else
node->parent->link[node->parent_link] = NULL;
}
static void
bintree_remove_onechild (struct bintree_node *node)
{
assert ((node->bl_left == NULL && node->bl_right != NULL) ||
(node->bl_left != NULL && node->bl_right == NULL));
if (node->bl_left)
{
if (node->parent == NULL)
{
node->tree->root = node->bl_left;
node->bl_left->parent = NULL;
}
else
{
node->parent->link[node->parent_link] = node->bl_left;
node->bl_left->parent = node->parent;
node->bl_left->parent_link = node->parent_link;
}
}
else if (node->bl_right)
{
if (node->parent == NULL)
{
node->tree->root = node->bl_right;
node->bl_right->parent = NULL;
}
else
{
node->parent->link[node->parent_link] = node->bl_right;
node->bl_right->parent = node->parent;
node->bl_right->parent_link = node->parent_link;
}
}
else
assert (0);
}
int
bintree_remove (void *data, struct bintree *tree)
{
int cmp;
struct bintree_node *node;
node = tree->root;
while (node)
{
if (tree->cmp)
cmp = (*tree->cmp) (node->data, data);
else
cmp = (node->data - data);
if (cmp == 0)
break;
if (cmp > 0)
node = node->bl_left;
else /* if (cmp < 0) */
node = node->bl_right;
}
if (node == NULL)
return -1;
if (node->bl_left == NULL && node->bl_right == NULL)
{
bintree_remove_nochild (node);
free (node);
tree->count--;
return 0;
}
if ((node->bl_left == NULL && node->bl_right != NULL) ||
(node->bl_left != NULL && node->bl_right == NULL))
{
bintree_remove_onechild (node);
free (node);
tree->count--;
return 0;
}
if (node->bl_left != NULL && node->bl_right != NULL)
{
struct bintree_node *successor;
/* find successor of the removing node */
successor = bintree_lookup_node_min (node->bl_right);
/* remove successor from tree */
if (successor->bl_right)
bintree_remove_onechild (successor);
else
bintree_remove_nochild (successor);
/* swap removing node with successor */
successor->parent = node->parent;
successor->parent_link = node->parent_link;
successor->bl_left = node->bl_left;
successor->bl_right = node->bl_right;
/* if the successor was the node->bl_right itself,
bintree_remove_**child may touch node->bl_right,
so only the successor->bl_right may be NULL
by above assignment */
successor->bl_left->parent = successor;
if (successor->bl_right)
successor->bl_right->parent = successor;
if (successor->parent == NULL)
tree->root = successor;
else
successor->parent->link[successor->parent_link] = successor;
free (node);
tree->count--;
return 0;
}
/* not reached */
return -1;
}
/* in-order traversal */
void
bintree_head (struct bintree *tree, struct bintree_node *node)
{
struct bintree_node *head;
head = bintree_lookup_node_min (tree->root);
if (head == NULL)
{
node->parent = NULL;
node->bl_left = NULL;
node->bl_right = NULL;
node->data = NULL;
return;
}
node->tree = head->tree;
node->parent = head->parent;
node->parent_link = head->parent_link;
node->bl_left = head->bl_left;
node->bl_right = head->bl_right;
node->data = head->data;
}
int
bintree_end (struct bintree_node *node)
{
if (node->parent || node->bl_left || node->bl_right || node->data)
return 0;
return 1;
}
#define GOTO_PROCED_SUBTREE_TOP(node) \
while (node->parent && node->parent->bl_right && \
node->parent->bl_right->data == node->data) \
{ \
node->data = node->parent->data; \
node->bl_left = node->parent->bl_left; \
node->bl_right = node->parent->bl_right; \
node->parent_link = node->parent->parent_link; \
node->parent = node->parent->parent; \
}
void
bintree_next (struct bintree_node *node)
{
struct bintree_node *next = NULL;
/* if node have just been removed, current point should have just been
replaced with its successor. that certainly will not be processed
yet, so process it */
if (node->parent == NULL)
{
if (node->tree->root == NULL)
{
assert (node->tree->count == 0);
node->parent = NULL;
node->bl_left = NULL;
node->bl_right = NULL;
node->data = NULL;
return;
}
else if (node->tree->root->data != node->data)
next = node->tree->root;
}
else if (node->parent->link[node->parent_link] == NULL)
{
if (node->parent_link == BL_LEFT)
next = node->parent;
else
{
GOTO_PROCED_SUBTREE_TOP (node);
next = node->parent;
}
}
else if (node->parent->link[node->parent_link]->data != node->data)
next = node->parent->link[node->parent_link];
if (next == NULL)
{
if (node->bl_right)
next = bintree_lookup_node_min (node->bl_right);
else
{
GOTO_PROCED_SUBTREE_TOP (node);
next = node->parent;
}
}
if (next)
{
node->tree = next->tree;
node->parent = next->parent;
node->parent_link = next->parent_link;
node->bl_left = next->bl_left;
node->bl_right = next->bl_right;
node->data = next->data;
}
else
{
node->parent = NULL;
node->bl_left = NULL;
node->bl_right = NULL;
node->data = NULL;
}
}
struct bintree *
bintree_create ()
{
struct bintree *tree;
tree = malloc (sizeof (struct bintree));
memset (tree, 0, sizeof (struct bintree));
return tree;
}
void
bintree_delete (struct bintree *tree)
{
struct bintree_node node;
for (bintree_head (tree, &node); ! bintree_end (&node);
bintree_next (&node))
bintree_remove (node.data, tree);
assert (tree->count == 0);
free (tree);
}
int indent_num = 0;
void
bintree_print_sub (void (*print) (int, void *), struct bintree_node *subroot)
{
if (subroot == NULL)
return;
if (subroot->bl_right)
{
indent_num++;
bintree_print_sub (print, subroot->bl_right);
indent_num--;
}
(*print) (indent_num, subroot->data);
if (subroot->bl_left)
{
indent_num++;
bintree_print_sub (print, subroot->bl_left);
indent_num--;
}
}
void
bintree_print (void (*print) (int, void *), struct bintree *tree)
{
indent_num = 0;
bintree_print_sub (print, tree->root);
}