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