src/avl.c

Sat, 28 Oct 2017 15:59:16 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 28 Oct 2017 15:59:16 +0200
changeset 260
a6184aff5108
parent 259
2f5dea574a75
child 287
98da78a1e69a
permissions
-rw-r--r--

rename LICENSE to COPYING to be distributed by autoconf

universe@192 1 /*
universe@192 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
universe@192 3 *
universe@259 4 * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved.
universe@192 5 *
universe@192 6 * Redistribution and use in source and binary forms, with or without
universe@192 7 * modification, are permitted provided that the following conditions are met:
universe@192 8 *
universe@192 9 * 1. Redistributions of source code must retain the above copyright
universe@192 10 * notice, this list of conditions and the following disclaimer.
universe@192 11 *
universe@192 12 * 2. Redistributions in binary form must reproduce the above copyright
universe@192 13 * notice, this list of conditions and the following disclaimer in the
universe@192 14 * documentation and/or other materials provided with the distribution.
universe@192 15 *
universe@192 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
universe@192 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
universe@192 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
universe@192 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
universe@192 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
universe@192 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
universe@192 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
universe@192 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
universe@192 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
universe@192 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
universe@192 26 * POSSIBILITY OF SUCH DAMAGE.
universe@192 27 */
universe@192 28
universe@251 29 #include "ucx/avl.h"
universe@251 30
universe@243 31 #include <limits.h>
universe@243 32
universe@195 33 #define ptrcast(ptr) ((void*)(ptr))
universe@216 34 #define alloc_tree(al) (UcxAVLTree*) almalloc((al), sizeof(UcxAVLTree))
universe@216 35 #define alloc_node(al) (UcxAVLNode*) almalloc((al), sizeof(UcxAVLNode))
universe@195 36
universe@195 37 static void ucx_avl_connect(UcxAVLTree *tree,
universe@195 38 UcxAVLNode *node, UcxAVLNode *child, intptr_t nullkey) {
universe@195 39 if (child) {
universe@195 40 child->parent = node;
universe@195 41 }
universe@195 42 // if child is NULL, nullkey decides if left or right pointer is cleared
universe@195 43 if (tree->cmpfunc(
universe@195 44 ptrcast(child ? child->key : nullkey),
universe@195 45 ptrcast(node->key), tree->userdata) > 0) {
universe@195 46 node->right = child;
universe@195 47 } else {
universe@195 48 node->left = child;
universe@195 49 }
universe@195 50 size_t lh = node->left ? node->left->height : 0;
universe@195 51 size_t rh = node->right ? node->right->height : 0;
universe@195 52 node->height = 1 + (lh > rh ? lh : rh);
universe@195 53 }
universe@195 54
universe@195 55 #define avlheight(node) ((node) ? (node)->height : 0)
universe@195 56
universe@195 57 static UcxAVLNode* avl_rotright(UcxAVLTree *tree, UcxAVLNode *l0) {
universe@195 58 UcxAVLNode *p = l0->parent;
universe@195 59 UcxAVLNode *l1 = l0->left;
universe@195 60 if (p) {
universe@195 61 ucx_avl_connect(tree, p, l1, 0);
universe@195 62 } else {
universe@195 63 l1->parent = NULL;
universe@195 64 }
universe@195 65 ucx_avl_connect(tree, l0, l1->right, l1->key);
universe@195 66 ucx_avl_connect(tree, l1, l0, 0);
universe@195 67 return l1;
universe@195 68 }
universe@195 69
universe@195 70 static UcxAVLNode* avl_rotleft(UcxAVLTree *tree, UcxAVLNode *l0) {
universe@195 71 UcxAVLNode *p = l0->parent;
universe@195 72 UcxAVLNode *l1 = l0->right;
universe@195 73 if (p) {
universe@195 74 ucx_avl_connect(tree, p, l1, 0);
universe@195 75 } else {
universe@195 76 l1->parent = NULL;
universe@195 77 }
universe@195 78 ucx_avl_connect(tree, l0, l1->left, l1->key);
universe@195 79 ucx_avl_connect(tree, l1, l0, 0);
universe@195 80 return l1;
universe@195 81 }
universe@195 82
universe@195 83 static void ucx_avl_balance(UcxAVLTree *tree, UcxAVLNode *n) {
universe@195 84 int lh = avlheight(n->left);
universe@195 85 int rh = avlheight(n->right);
universe@195 86 n->height = 1 + (lh > rh ? lh : rh);
universe@195 87
universe@195 88 if (lh - rh == 2) {
universe@195 89 UcxAVLNode *c = n->left;
universe@195 90 if (avlheight(c->right) - avlheight(c->left) == 1) {
universe@195 91 avl_rotleft(tree, c);
universe@195 92 }
universe@195 93 n = avl_rotright(tree, n);
universe@195 94 } else if (rh - lh == 2) {
universe@195 95 UcxAVLNode *c = n->right;
universe@195 96 if (avlheight(c->left) - avlheight(c->right) == 1) {
universe@195 97 avl_rotright(tree, c);
universe@195 98 }
universe@195 99 n = avl_rotleft(tree, n);
universe@195 100 }
universe@195 101
universe@195 102 if (n->parent) {
universe@195 103 ucx_avl_balance(tree, n->parent);
universe@195 104 } else {
universe@195 105 tree->root = n;
universe@195 106 }
universe@195 107 }
universe@195 108
universe@194 109 UcxAVLTree *ucx_avl_new(cmp_func cmpfunc) {
universe@194 110 return ucx_avl_new_a(cmpfunc, ucx_default_allocator());
universe@194 111 }
universe@194 112
universe@194 113 UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator) {
universe@216 114 UcxAVLTree* tree = alloc_tree(allocator);
universe@194 115 if (tree) {
universe@194 116 tree->allocator = allocator;
universe@194 117 tree->cmpfunc = cmpfunc;
universe@194 118 tree->root = NULL;
universe@194 119 tree->userdata = NULL;
universe@194 120 }
universe@194 121
universe@194 122 return tree;
universe@194 123 }
universe@194 124
universe@196 125 static void ucx_avl_free_node(UcxAllocator *al, UcxAVLNode *node) {
universe@196 126 if (node) {
universe@196 127 ucx_avl_free_node(al, node->left);
universe@196 128 ucx_avl_free_node(al, node->right);
universe@196 129 alfree(al, node);
universe@196 130 }
universe@196 131 }
universe@196 132
universe@196 133 void ucx_avl_free(UcxAVLTree *tree) {
universe@196 134 UcxAllocator *al = tree->allocator;
universe@196 135 ucx_avl_free_node(al, tree->root);
universe@196 136 alfree(al, tree);
universe@196 137 }
universe@196 138
universe@205 139 UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key) {
universe@195 140 UcxAVLNode *n = tree->root;
universe@195 141 int cmpresult;
universe@195 142 while (n && (cmpresult = tree->cmpfunc(
universe@195 143 ptrcast(key), ptrcast(n->key), tree->userdata))) {
universe@195 144 n = cmpresult > 0 ? n->right : n->left;
universe@195 145 }
universe@204 146 return n;
universe@204 147 }
universe@204 148
universe@204 149 void *ucx_avl_get(UcxAVLTree *tree, intptr_t key) {
universe@205 150 UcxAVLNode *n = ucx_avl_get_node(tree, key);
universe@195 151 return n ? n->value : NULL;
universe@194 152 }
universe@194 153
universe@243 154 UcxAVLNode *ucx_avl_find_node(UcxAVLTree *tree, intptr_t key,
universe@243 155 distance_func dfnc, int mode) {
universe@243 156 UcxAVLNode *n = tree->root;
universe@243 157 UcxAVLNode *closest = NULL;
universe@243 158
universe@243 159 intmax_t cmpresult;
universe@243 160 intmax_t closest_dist;
universe@243 161 closest_dist = mode == UCX_AVL_FIND_LOWER_BOUNDED ? INTMAX_MIN : INTMAX_MAX;
universe@243 162
universe@243 163 while (n && (cmpresult = dfnc(
universe@243 164 ptrcast(key), ptrcast(n->key), tree->userdata))) {
universe@243 165 if (mode == UCX_AVL_FIND_CLOSEST) {
universe@243 166 intmax_t dist = cmpresult;
universe@243 167 if (dist < 0) dist *= -1;
universe@243 168 if (dist < closest_dist) {
universe@243 169 closest_dist = dist;
universe@243 170 closest = n;
universe@243 171 }
universe@243 172 } else if (mode == UCX_AVL_FIND_LOWER_BOUNDED && cmpresult <= 0) {
universe@243 173 if (cmpresult > closest_dist) {
universe@243 174 closest_dist = cmpresult;
universe@243 175 closest = n;
universe@243 176 }
universe@243 177 } else if (mode == UCX_AVL_FIND_UPPER_BOUNDED && cmpresult >= 0) {
universe@243 178 if (cmpresult < closest_dist) {
universe@243 179 closest_dist = cmpresult;
universe@243 180 closest = n;
universe@243 181 }
universe@243 182 }
universe@243 183 n = cmpresult > 0 ? n->right : n->left;
universe@243 184 }
universe@243 185 return n ? n : closest;
universe@243 186 }
universe@243 187
universe@243 188 void *ucx_avl_find(UcxAVLTree *tree, intptr_t key,
universe@243 189 distance_func dfnc, int mode) {
universe@243 190 UcxAVLNode *n = ucx_avl_find_node(tree, key, dfnc, mode);
universe@243 191 return n ? n->value : NULL;
universe@243 192 }
universe@243 193
universe@204 194 int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value) {
universe@204 195 return ucx_avl_put_s(tree, key, value, NULL);
universe@204 196 }
universe@204 197
universe@204 198 int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value,
universe@204 199 void **oldvalue) {
universe@195 200 if (tree->root) {
universe@195 201 UcxAVLNode *n = tree->root;
universe@195 202 int cmpresult;
universe@197 203 while ((cmpresult = tree->cmpfunc(
universe@197 204 ptrcast(key), ptrcast(n->key), tree->userdata))) {
universe@195 205 UcxAVLNode *m = cmpresult > 0 ? n->right : n->left;
universe@195 206 if (m) {
universe@195 207 n = m;
universe@195 208 } else {
universe@195 209 break;
universe@195 210 }
universe@195 211 }
universe@195 212
universe@195 213 if (cmpresult) {
universe@216 214 UcxAVLNode* e = alloc_node(tree->allocator);
universe@204 215 if (e) {
universe@204 216 e->key = key; e->value = value; e->height = 1;
universe@204 217 e->parent = e->left = e->right = NULL;
universe@204 218 ucx_avl_connect(tree, n, e, 0);
universe@204 219 ucx_avl_balance(tree, n);
universe@204 220 return 0;
universe@204 221 } else {
universe@204 222 return 1;
universe@204 223 }
universe@195 224 } else {
universe@204 225 if (oldvalue) {
universe@204 226 *oldvalue = n->value;
universe@204 227 }
universe@195 228 n->value = value;
universe@204 229 return 0;
universe@195 230 }
universe@195 231 } else {
universe@216 232 tree->root = alloc_node(tree->allocator);
universe@204 233 if (tree->root) {
universe@204 234 tree->root->key = key; tree->root->value = value;
universe@204 235 tree->root->height = 1;
universe@204 236 tree->root->parent = tree->root->left = tree->root->right = NULL;
universe@204 237
universe@204 238 if (oldvalue) {
universe@204 239 *oldvalue = NULL;
universe@204 240 }
universe@204 241
universe@204 242 return 0;
universe@204 243 } else {
universe@204 244 return 1;
universe@204 245 }
universe@195 246 }
universe@194 247 }
universe@194 248
universe@204 249 int ucx_avl_remove(UcxAVLTree *tree, intptr_t key) {
universe@204 250 return ucx_avl_remove_s(tree, key, NULL, NULL);
universe@204 251 }
universe@204 252
universe@205 253 int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node) {
universe@204 254 return ucx_avl_remove_s(tree, node->key, NULL, NULL);
universe@204 255 }
universe@204 256
universe@204 257 int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key,
universe@204 258 intptr_t *oldkey, void **oldvalue) {
universe@204 259
universe@195 260 UcxAVLNode *n = tree->root;
universe@195 261 int cmpresult;
universe@195 262 while (n && (cmpresult = tree->cmpfunc(
universe@195 263 ptrcast(key), ptrcast(n->key), tree->userdata))) {
universe@195 264 n = cmpresult > 0 ? n->right : n->left;
universe@195 265 }
universe@195 266 if (n) {
universe@204 267 if (oldkey) {
universe@204 268 *oldkey = n->key;
universe@204 269 }
universe@204 270 if (oldvalue) {
universe@204 271 *oldvalue = n->value;
universe@204 272 }
universe@204 273
universe@195 274 UcxAVLNode *p = n->parent;
universe@195 275 if (n->left && n->right) {
universe@195 276 UcxAVLNode *s = n->right;
universe@195 277 while (s->left) {
universe@195 278 s = s->left;
universe@195 279 }
universe@195 280 ucx_avl_connect(tree, s->parent, s->right, s->key);
universe@195 281 n->key = s->key; n->value = s->value;
universe@195 282 p = s->parent;
universe@196 283 alfree(tree->allocator, s);
universe@195 284 } else {
universe@195 285 if (p) {
universe@195 286 ucx_avl_connect(tree, p, n->right ? n->right:n->left, n->key);
universe@195 287 } else {
universe@195 288 tree->root = n->right ? n->right : n->left;
olaf@203 289 if (tree->root) {
olaf@202 290 tree->root->parent = NULL;
olaf@202 291 }
universe@195 292 }
universe@196 293 alfree(tree->allocator, n);
universe@195 294 }
universe@195 295
universe@195 296 if (p) {
universe@195 297 ucx_avl_balance(tree, p);
universe@195 298 }
universe@204 299
universe@204 300 return 0;
universe@195 301 } else {
universe@204 302 return 1;
universe@195 303 }
universe@194 304 }
universe@194 305
universe@199 306 static size_t ucx_avl_countn(UcxAVLNode *node) {
universe@199 307 if (node) {
universe@199 308 return 1 + ucx_avl_countn(node->left) + ucx_avl_countn(node->right);
universe@199 309 } else {
universe@199 310 return 0;
universe@199 311 }
universe@199 312 }
universe@199 313
universe@199 314 size_t ucx_avl_count(UcxAVLTree *tree) {
universe@199 315 return ucx_avl_countn(tree->root);
universe@199 316 }
universe@245 317
universe@245 318 UcxAVLNode* ucx_avl_pred(UcxAVLNode* node) {
universe@245 319 if (node->left) {
universe@245 320 UcxAVLNode* n = node->left;
universe@245 321 while (n->right) {
universe@245 322 n = n->right;
universe@245 323 }
universe@245 324 return n;
universe@245 325 } else {
universe@245 326 UcxAVLNode* n = node;
universe@245 327 while (n->parent) {
universe@245 328 if (n->parent->right == n) {
universe@245 329 return n->parent;
universe@245 330 } else {
universe@245 331 n = n->parent;
universe@245 332 }
universe@245 333 }
universe@245 334 return NULL;
universe@245 335 }
universe@245 336 }
universe@245 337
universe@245 338 UcxAVLNode* ucx_avl_succ(UcxAVLNode* node) {
universe@245 339 if (node->right) {
universe@245 340 UcxAVLNode* n = node->right;
universe@245 341 while (n->left) {
universe@245 342 n = n->left;
universe@245 343 }
universe@245 344 return n;
universe@245 345 } else {
universe@245 346 UcxAVLNode* n = node;
universe@245 347 while (n->parent) {
universe@245 348 if (n->parent->left == n) {
universe@245 349 return n->parent;
universe@245 350 } else {
universe@245 351 n = n->parent;
universe@245 352 }
universe@245 353 }
universe@245 354 return NULL;
universe@245 355 }
universe@245 356 }

mercurial