/** * collectd - src/utils_avltree.c * Copyright (C) 2006,2007 Florian octo Forster * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Authors: * Florian octo Forster **/ #include #include #include "utils/avltree/avltree.h" #define BALANCE(n) \ ((((n)->left == NULL) ? 0 : (n)->left->height) - \ (((n)->right == NULL) ? 0 : (n)->right->height)) /* * private data types */ struct c_avl_node_s { void *key; void *value; int height; struct c_avl_node_s *left; struct c_avl_node_s *right; struct c_avl_node_s *parent; }; typedef struct c_avl_node_s c_avl_node_t; struct c_avl_tree_s { c_avl_node_t *root; int (*compare)(const void *, const void *); int size; }; struct c_avl_iterator_s { c_avl_tree_t *tree; c_avl_node_t *node; }; /* * private functions */ #if 0 static void verify_tree (c_avl_node_t *n) { if (n == NULL) return; verify_tree (n->left); verify_tree (n->right); assert ((BALANCE (n) >= -1) && (BALANCE (n) <= 1)); assert ((n->parent == NULL) || (n->parent->right == n) || (n->parent->left == n)); } /* void verify_tree */ #else #define verify_tree(n) /**/ #endif static void free_node(c_avl_node_t *n) { if (n == NULL) return; if (n->left != NULL) free_node(n->left); if (n->right != NULL) free_node(n->right); free(n); } static int calc_height(c_avl_node_t *n) { int height_left; int height_right; if (n == NULL) return 0; height_left = (n->left == NULL) ? 0 : n->left->height; height_right = (n->right == NULL) ? 0 : n->right->height; return ((height_left > height_right) ? height_left : height_right) + 1; } /* int calc_height */ static c_avl_node_t *search(c_avl_tree_t *t, const void *key) { c_avl_node_t *n; int cmp; n = t->root; while (n != NULL) { cmp = t->compare(key, n->key); if (cmp == 0) return n; else if (cmp < 0) n = n->left; else n = n->right; } return NULL; } /* (x) (y) * / \ / \ * (y) /\ /\ (x) * / \ /_c\ ==> / a\ / \ * /\ /\ /____\/\ /\ * / a\ /_b\ /_b\ /_c\ * /____\ */ static c_avl_node_t *rotate_right(c_avl_tree_t *t, c_avl_node_t *x) { c_avl_node_t *p; c_avl_node_t *y; c_avl_node_t *b; assert(x != NULL); assert(x->left != NULL); p = x->parent; y = x->left; b = y->right; x->left = b; if (b != NULL) b->parent = x; x->parent = y; y->right = x; y->parent = p; assert((p == NULL) || (p->left == x) || (p->right == x)); if (p == NULL) t->root = y; else if (p->left == x) p->left = y; else p->right = y; x->height = calc_height(x); y->height = calc_height(y); return y; } /* void rotate_right */ /* * (x) (y) * / \ / \ * /\ (y) (x) /\ * /_a\ / \ ==> / \ / c\ * /\ /\ /\ /\/____\ * /_b\ / c\ /_a\ /_b\ * /____\ */ static c_avl_node_t *rotate_left(c_avl_tree_t *t, c_avl_node_t *x) { c_avl_node_t *p; c_avl_node_t *y; c_avl_node_t *b; assert(x != NULL); assert(x->right != NULL); p = x->parent; y = x->right; b = y->left; x->right = b; if (b != NULL) b->parent = x; x->parent = y; y->left = x; y->parent = p; assert((p == NULL) || (p->left == x) || (p->right == x)); if (p == NULL) t->root = y; else if (p->left == x) p->left = y; else p->right = y; x->height = calc_height(x); y->height = calc_height(y); return y; } /* void rotate_left */ static c_avl_node_t *rotate_left_right(c_avl_tree_t *t, c_avl_node_t *x) { rotate_left(t, x->left); return rotate_right(t, x); } /* void rotate_left_right */ static c_avl_node_t *rotate_right_left(c_avl_tree_t *t, c_avl_node_t *x) { rotate_right(t, x->right); return rotate_left(t, x); } /* void rotate_right_left */ static void rebalance(c_avl_tree_t *t, c_avl_node_t *n) { int b_top; int b_bottom; while (n != NULL) { b_top = BALANCE(n); assert((b_top >= -2) && (b_top <= 2)); if (b_top == -2) { assert(n->right != NULL); b_bottom = BALANCE(n->right); assert((b_bottom >= -1) && (b_bottom <= 1)); if (b_bottom == 1) n = rotate_right_left(t, n); else n = rotate_left(t, n); } else if (b_top == 2) { assert(n->left != NULL); b_bottom = BALANCE(n->left); assert((b_bottom >= -1) && (b_bottom <= 1)); if (b_bottom == -1) n = rotate_left_right(t, n); else n = rotate_right(t, n); } else { int height = calc_height(n); if (height == n->height) break; n->height = height; } assert(n->height == calc_height(n)); n = n->parent; } /* while (n != NULL) */ } /* void rebalance */ static c_avl_node_t *c_avl_node_next(c_avl_node_t *n) { c_avl_node_t *r; /* return node */ if (n == NULL) { return NULL; } /* If we can't descent any further, we have to backtrack to the first * parent that's bigger than we, i. e. who's _left_ child we are. */ if (n->right == NULL) { r = n->parent; while ((r != NULL) && (r->parent != NULL)) { if (r->left == n) break; n = r; r = n->parent; } /* n->right == NULL && r == NULL => t is root and has no next * r->left != n => r->right = n => r->parent == NULL */ if ((r == NULL) || (r->left != n)) { assert((r == NULL) || (r->parent == NULL)); return NULL; } else { assert(r->left == n); return r; } } else { r = n->right; while (r->left != NULL) r = r->left; } return r; } /* c_avl_node_t *c_avl_node_next */ static c_avl_node_t *c_avl_node_prev(c_avl_node_t *n) { c_avl_node_t *r; /* return node */ if (n == NULL) { return NULL; } /* If we can't descent any further, we have to backtrack to the first * parent that's smaller than we, i. e. who's _right_ child we are. */ if (n->left == NULL) { r = n->parent; while ((r != NULL) && (r->parent != NULL)) { if (r->right == n) break; n = r; r = n->parent; } /* n->left == NULL && r == NULL => t is root and has no next * r->right != n => r->left = n => r->parent == NULL */ if ((r == NULL) || (r->right != n)) { assert((r == NULL) || (r->parent == NULL)); return NULL; } else { assert(r->right == n); return r; } } else { r = n->left; while (r->right != NULL) r = r->right; } return r; } /* c_avl_node_t *c_avl_node_prev */ static int _remove(c_avl_tree_t *t, c_avl_node_t *n) { assert((t != NULL) && (n != NULL)); if ((n->left != NULL) && (n->right != NULL)) { c_avl_node_t *r; /* replacement node */ if (BALANCE(n) > 0) /* left subtree is higher */ { assert(n->left != NULL); r = c_avl_node_prev(n); } else /* right subtree is higher */ { assert(n->right != NULL); r = c_avl_node_next(n); } assert((r->left == NULL) || (r->right == NULL)); /* copy content */ n->key = r->key; n->value = r->value; n = r; } assert((n->left == NULL) || (n->right == NULL)); if ((n->left == NULL) && (n->right == NULL)) { /* Deleting a leave is easy */ if (n->parent == NULL) { assert(t->root == n); t->root = NULL; } else { assert((n->parent->left == n) || (n->parent->right == n)); if (n->parent->left == n) n->parent->left = NULL; else n->parent->right = NULL; rebalance(t, n->parent); } free_node(n); } else if (n->left == NULL) { assert(BALANCE(n) == -1); assert((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n)); if (n->parent == NULL) { assert(t->root == n); t->root = n->right; } else if (n->parent->left == n) { n->parent->left = n->right; } else { n->parent->right = n->right; } n->right->parent = n->parent; if (n->parent != NULL) rebalance(t, n->parent); n->right = NULL; free_node(n); } else if (n->right == NULL) { assert(BALANCE(n) == 1); assert((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n)); if (n->parent == NULL) { assert(t->root == n); t->root = n->left; } else if (n->parent->left == n) { n->parent->left = n->left; } else { n->parent->right = n->left; } n->left->parent = n->parent; if (n->parent != NULL) rebalance(t, n->parent); n->left = NULL; free_node(n); } else { assert(0); } return 0; } /* void *_remove */ /* * public functions */ c_avl_tree_t *c_avl_create(int (*compare)(const void *, const void *)) { c_avl_tree_t *t; if (compare == NULL) return NULL; if ((t = malloc(sizeof(*t))) == NULL) return NULL; t->root = NULL; t->compare = compare; t->size = 0; return t; } void c_avl_destroy(c_avl_tree_t *t) { if (t == NULL) return; free_node(t->root); free(t); } int c_avl_insert(c_avl_tree_t *t, void *key, void *value) { c_avl_node_t *new; c_avl_node_t *nptr; int cmp; if ((new = malloc(sizeof(*new))) == NULL) return -1; new->key = key; new->value = value; new->height = 1; new->left = NULL; new->right = NULL; if (t->root == NULL) { new->parent = NULL; t->root = new; t->size = 1; return 0; } nptr = t->root; while (42) { cmp = t->compare(nptr->key, new->key); if (cmp == 0) { free_node(new); return 1; } else if (cmp < 0) { /* nptr < new */ if (nptr->right == NULL) { nptr->right = new; new->parent = nptr; rebalance(t, nptr); break; } else { nptr = nptr->right; } } else /* if (cmp > 0) */ { /* nptr > new */ if (nptr->left == NULL) { nptr->left = new; new->parent = nptr; rebalance(t, nptr); break; } else { nptr = nptr->left; } } } /* while (42) */ verify_tree(t->root); ++t->size; return 0; } /* int c_avl_insert */ int c_avl_remove(c_avl_tree_t *t, const void *key, void **rkey, void **rvalue) { c_avl_node_t *n; int status; assert(t != NULL); n = search(t, key); if (n == NULL) return -1; if (rkey != NULL) *rkey = n->key; if (rvalue != NULL) *rvalue = n->value; status = _remove(t, n); verify_tree(t->root); --t->size; return status; } /* void *c_avl_remove */ int c_avl_get(c_avl_tree_t *t, const void *key, void **value) { c_avl_node_t *n; assert(t != NULL); n = search(t, key); if (n == NULL) return -1; if (value != NULL) *value = n->value; return 0; } int c_avl_pick(c_avl_tree_t *t, void **key, void **value) { c_avl_node_t *n; c_avl_node_t *p; assert(t != NULL); if ((key == NULL) || (value == NULL)) return -1; if (t->root == NULL) return -1; n = t->root; while ((n->left != NULL) || (n->right != NULL)) { if (n->left == NULL) { n = n->right; continue; } else if (n->right == NULL) { n = n->left; continue; } if (n->left->height > n->right->height) n = n->left; else n = n->right; } p = n->parent; if (p == NULL) t->root = NULL; else if (p->left == n) p->left = NULL; else p->right = NULL; *key = n->key; *value = n->value; free_node(n); --t->size; rebalance(t, p); return 0; } /* int c_avl_pick */ c_avl_iterator_t *c_avl_get_iterator(c_avl_tree_t *t) { c_avl_iterator_t *iter; if (t == NULL) return NULL; iter = calloc(1, sizeof(*iter)); if (iter == NULL) return NULL; iter->tree = t; return iter; } /* c_avl_iterator_t *c_avl_get_iterator */ int c_avl_iterator_next(c_avl_iterator_t *iter, void **key, void **value) { c_avl_node_t *n; if ((iter == NULL) || (key == NULL) || (value == NULL)) return -1; if (iter->node == NULL) { for (n = iter->tree->root; n != NULL; n = n->left) if (n->left == NULL) break; iter->node = n; } else { n = c_avl_node_next(iter->node); } if (n == NULL) return -1; iter->node = n; *key = n->key; *value = n->value; return 0; } /* int c_avl_iterator_next */ int c_avl_iterator_prev(c_avl_iterator_t *iter, void **key, void **value) { c_avl_node_t *n; if ((iter == NULL) || (key == NULL) || (value == NULL)) return -1; if (iter->node == NULL) { for (n = iter->tree->root; n != NULL; n = n->right) if (n->right == NULL) break; iter->node = n; } else { n = c_avl_node_prev(iter->node); } if (n == NULL) return -1; iter->node = n; *key = n->key; *value = n->value; return 0; } /* int c_avl_iterator_prev */ void c_avl_iterator_destroy(c_avl_iterator_t *iter) { free(iter); } int c_avl_size(c_avl_tree_t *t) { if (t == NULL) return 0; return t->size; }