src/glpavl.c
changeset 1 c445c931472f
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/glpavl.c	Mon Dec 06 13:09:21 2010 +0100
     1.3 @@ -0,0 +1,357 @@
     1.4 +/* glpavl.c (binary search tree) */
     1.5 +
     1.6 +/***********************************************************************
     1.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
     1.8 +*
     1.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
    1.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
    1.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
    1.12 +*  E-mail: <mao@gnu.org>.
    1.13 +*
    1.14 +*  GLPK is free software: you can redistribute it and/or modify it
    1.15 +*  under the terms of the GNU General Public License as published by
    1.16 +*  the Free Software Foundation, either version 3 of the License, or
    1.17 +*  (at your option) any later version.
    1.18 +*
    1.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
    1.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    1.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    1.22 +*  License for more details.
    1.23 +*
    1.24 +*  You should have received a copy of the GNU General Public License
    1.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
    1.26 +***********************************************************************/
    1.27 +
    1.28 +#include "glpavl.h"
    1.29 +
    1.30 +AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
    1.31 +      const void *key2), void *info)
    1.32 +{     /* create AVL tree */
    1.33 +      AVL *tree;
    1.34 +      tree = xmalloc(sizeof(AVL));
    1.35 +      tree->pool = dmp_create_pool();
    1.36 +      tree->root = NULL;
    1.37 +      tree->fcmp = fcmp;
    1.38 +      tree->info = info;
    1.39 +      tree->size = 0;
    1.40 +      tree->height = 0;
    1.41 +      return tree;
    1.42 +}
    1.43 +
    1.44 +int avl_strcmp(void *info, const void *key1, const void *key2)
    1.45 +{     /* compare character string keys */
    1.46 +      xassert(info == info);
    1.47 +      return strcmp(key1, key2);
    1.48 +}
    1.49 +
    1.50 +static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node);
    1.51 +
    1.52 +AVLNODE *avl_insert_node(AVL *tree, const void *key)
    1.53 +{     /* insert new node into AVL tree */
    1.54 +      AVLNODE *p, *q, *r;
    1.55 +      short int flag;
    1.56 +      /* find an appropriate point for insertion */
    1.57 +      p = NULL; q = tree->root;
    1.58 +      while (q != NULL)
    1.59 +      {  p = q;
    1.60 +         if (tree->fcmp(tree->info, key, p->key) <= 0)
    1.61 +         {  flag = 0;
    1.62 +            q = p->left;
    1.63 +            p->rank++;
    1.64 +         }
    1.65 +         else
    1.66 +         {  flag = 1;
    1.67 +            q = p->right;
    1.68 +         }
    1.69 +      }
    1.70 +      /* create new node and insert it into the tree */
    1.71 +      r = dmp_get_atom(tree->pool, sizeof(AVLNODE));
    1.72 +      r->key = key; r->type = 0; r->link = NULL;
    1.73 +      r->rank = 1; r->up = p;
    1.74 +      r->flag = (short int)(p == NULL ? 0 : flag);
    1.75 +      r->bal = 0; r->left = NULL; r->right = NULL;
    1.76 +      tree->size++;
    1.77 +      if (p == NULL)
    1.78 +         tree->root = r;
    1.79 +      else
    1.80 +         if (flag == 0) p->left = r; else p->right = r;
    1.81 +      /* go upstairs to the root and correct all subtrees affected by
    1.82 +         insertion */
    1.83 +      while (p != NULL)
    1.84 +      {  if (flag == 0)
    1.85 +         {  /* the height of the left subtree of [p] is increased */
    1.86 +            if (p->bal > 0)
    1.87 +            {  p->bal = 0;
    1.88 +               break;
    1.89 +            }
    1.90 +            if (p->bal < 0)
    1.91 +            {  rotate_subtree(tree, p);
    1.92 +               break;
    1.93 +            }
    1.94 +            p->bal = -1; flag = p->flag; p = p->up;
    1.95 +         }
    1.96 +         else
    1.97 +         {  /* the height of the right subtree of [p] is increased */
    1.98 +            if (p->bal < 0)
    1.99 +            {  p->bal = 0;
   1.100 +               break;
   1.101 +            }
   1.102 +            if (p->bal > 0)
   1.103 +            {  rotate_subtree(tree, p);
   1.104 +               break;
   1.105 +            }
   1.106 +            p->bal = +1; flag = p->flag; p = p->up;
   1.107 +         }
   1.108 +      }
   1.109 +      /* if the root has been reached, the height of the entire tree is
   1.110 +         increased */
   1.111 +      if (p == NULL) tree->height++;
   1.112 +      return r;
   1.113 +}
   1.114 +
   1.115 +void avl_set_node_type(AVLNODE *node, int type)
   1.116 +{     /* assign the type field of specified node */
   1.117 +      node->type = type;
   1.118 +      return;
   1.119 +}
   1.120 +
   1.121 +void avl_set_node_link(AVLNODE *node, void *link)
   1.122 +{     /* assign the link field of specified node */
   1.123 +      node->link = link;
   1.124 +      return;
   1.125 +}
   1.126 +
   1.127 +AVLNODE *avl_find_node(AVL *tree, const void *key)
   1.128 +{     /* find node in AVL tree */
   1.129 +      AVLNODE *p;
   1.130 +      int c;
   1.131 +      p = tree->root;
   1.132 +      while (p != NULL)
   1.133 +      {  c = tree->fcmp(tree->info, key, p->key);
   1.134 +         if (c == 0) break;
   1.135 +         p = (c < 0 ? p->left : p->right);
   1.136 +      }
   1.137 +      return p;
   1.138 +}
   1.139 +
   1.140 +int avl_get_node_type(AVLNODE *node)
   1.141 +{     /* retrieve the type field of specified node */
   1.142 +      return node->type;
   1.143 +}
   1.144 +
   1.145 +void *avl_get_node_link(AVLNODE *node)
   1.146 +{     /* retrieve the link field of specified node */
   1.147 +      return node->link;
   1.148 +}
   1.149 +
   1.150 +static AVLNODE *find_next_node(AVL *tree, AVLNODE *node)
   1.151 +{     /* find next node in AVL tree */
   1.152 +      AVLNODE *p, *q;
   1.153 +      if (tree->root == NULL) return NULL;
   1.154 +      p = node;
   1.155 +      q = (p == NULL ? tree->root : p->right);
   1.156 +      if (q == NULL)
   1.157 +      {  /* go upstairs from the left subtree */
   1.158 +         for (;;)
   1.159 +         {  q = p->up;
   1.160 +            if (q == NULL) break;
   1.161 +            if (p->flag == 0) break;
   1.162 +            p = q;
   1.163 +         }
   1.164 +      }
   1.165 +      else
   1.166 +      {  /* go downstairs into the right subtree */
   1.167 +         for (;;)
   1.168 +         {  p = q->left;
   1.169 +            if (p == NULL) break;
   1.170 +            q = p;
   1.171 +         }
   1.172 +      }
   1.173 +      return q;
   1.174 +}
   1.175 +
   1.176 +void avl_delete_node(AVL *tree, AVLNODE *node)
   1.177 +{     /* delete specified node from AVL tree */
   1.178 +      AVLNODE *f, *p, *q, *r, *s, *x, *y;
   1.179 +      short int flag;
   1.180 +      p = node;
   1.181 +      /* if both subtrees of the specified node are non-empty, the node
   1.182 +         should be interchanged with the next one, at least one subtree
   1.183 +         of which is always empty */
   1.184 +      if (p->left == NULL || p->right == NULL) goto skip;
   1.185 +      f = p->up; q = p->left;
   1.186 +      r = find_next_node(tree, p); s = r->right;
   1.187 +      if (p->right == r)
   1.188 +      {  if (f == NULL)
   1.189 +            tree->root = r;
   1.190 +         else
   1.191 +            if (p->flag == 0) f->left = r; else f->right = r;
   1.192 +         r->rank = p->rank; r->up = f;
   1.193 +         r->flag = p->flag; r->bal = p->bal;
   1.194 +         r->left = q; r->right = p;
   1.195 +         q->up = r;
   1.196 +         p->rank = 1; p->up = r; p->flag = 1;
   1.197 +         p->bal = (short int)(s == NULL ? 0 : +1);
   1.198 +         p->left = NULL; p->right = s;
   1.199 +         if (s != NULL) s->up = p;
   1.200 +      }
   1.201 +      else
   1.202 +      {  x = p->right; y = r->up;
   1.203 +         if (f == NULL)
   1.204 +            tree->root = r;
   1.205 +         else
   1.206 +            if (p->flag == 0) f->left = r; else f->right = r;
   1.207 +         r->rank = p->rank; r->up = f;
   1.208 +         r->flag = p->flag; r->bal = p->bal;
   1.209 +         r->left = q; r->right = x;
   1.210 +         q->up = r; x->up = r; y->left = p;
   1.211 +         p->rank = 1; p->up = y; p->flag = 0;
   1.212 +         p->bal = (short int)(s == NULL ? 0 : +1);
   1.213 +         p->left = NULL; p->right = s;
   1.214 +         if (s != NULL) s->up = p;
   1.215 +      }
   1.216 +skip: /* now the specified node [p] has at least one empty subtree;
   1.217 +         go upstairs to the root and adjust the rank field of all nodes
   1.218 +         affected by deletion */
   1.219 +      q = p; f = q->up;
   1.220 +      while (f != NULL)
   1.221 +      {  if (q->flag == 0) f->rank--;
   1.222 +         q = f; f = q->up;
   1.223 +      }
   1.224 +      /* delete the specified node from the tree */
   1.225 +      f = p->up; flag = p->flag;
   1.226 +      q = p->left != NULL ? p->left : p->right;
   1.227 +      if (f == NULL)
   1.228 +         tree->root = q;
   1.229 +      else
   1.230 +         if (flag == 0) f->left = q; else f->right = q;
   1.231 +      if (q != NULL) q->up = f, q->flag = flag;
   1.232 +      tree->size--;
   1.233 +      /* go upstairs to the root and correct all subtrees affected by
   1.234 +         deletion */
   1.235 +      while (f != NULL)
   1.236 +      {  if (flag == 0)
   1.237 +         {  /* the height of the left subtree of [f] is decreased */
   1.238 +            if (f->bal == 0)
   1.239 +            {  f->bal = +1;
   1.240 +               break;
   1.241 +            }
   1.242 +            if (f->bal < 0)
   1.243 +               f->bal = 0;
   1.244 +            else
   1.245 +            {  f = rotate_subtree(tree, f);
   1.246 +               if (f->bal < 0) break;
   1.247 +            }
   1.248 +            flag = f->flag; f = f->up;
   1.249 +         }
   1.250 +         else
   1.251 +         {  /* the height of the right subtree of [f] is decreased */
   1.252 +            if (f->bal == 0)
   1.253 +            {  f->bal = -1;
   1.254 +               break;
   1.255 +            }
   1.256 +            if (f->bal > 0)
   1.257 +               f->bal = 0;
   1.258 +            else
   1.259 +            {  f = rotate_subtree(tree, f);
   1.260 +               if (f->bal > 0) break;
   1.261 +            }
   1.262 +            flag = f->flag; f = f->up;
   1.263 +         }
   1.264 +      }
   1.265 +      /* if the root has been reached, the height of the entire tree is
   1.266 +         decreased */
   1.267 +      if (f == NULL) tree->height--;
   1.268 +      /* returns the deleted node to the memory pool */
   1.269 +      dmp_free_atom(tree->pool, p, sizeof(AVLNODE));
   1.270 +      return;
   1.271 +}
   1.272 +
   1.273 +static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node)
   1.274 +{     /* restore balance of AVL subtree */
   1.275 +      AVLNODE *f, *p, *q, *r, *x, *y;
   1.276 +      xassert(node != NULL);
   1.277 +      p = node;
   1.278 +      if (p->bal < 0)
   1.279 +      {  /* perform negative (left) rotation */
   1.280 +         f = p->up; q = p->left; r = q->right;
   1.281 +         if (q->bal <= 0)
   1.282 +         {  /* perform single negative rotation */
   1.283 +            if (f == NULL)
   1.284 +               tree->root = q;
   1.285 +            else
   1.286 +               if (p->flag == 0) f->left = q; else f->right = q;
   1.287 +            p->rank -= q->rank;
   1.288 +            q->up = f; q->flag = p->flag; q->bal++; q->right = p;
   1.289 +            p->up = q; p->flag = 1;
   1.290 +            p->bal = (short int)(-q->bal); p->left = r;
   1.291 +            if (r != NULL) r->up = p, r->flag = 0;
   1.292 +            node = q;
   1.293 +         }
   1.294 +         else
   1.295 +         {  /* perform double negative rotation */
   1.296 +            x = r->left; y = r->right;
   1.297 +            if (f == NULL)
   1.298 +               tree->root = r;
   1.299 +            else
   1.300 +               if (p->flag == 0) f->left = r; else f->right = r;
   1.301 +            p->rank -= (q->rank + r->rank);
   1.302 +            r->rank += q->rank;
   1.303 +            p->bal = (short int)(r->bal >= 0 ? 0 : +1);
   1.304 +            q->bal = (short int)(r->bal <= 0 ? 0 : -1);
   1.305 +            r->up = f; r->flag = p->flag; r->bal = 0;
   1.306 +            r->left = q; r->right = p;
   1.307 +            p->up = r; p->flag = 1; p->left = y;
   1.308 +            q->up = r; q->flag = 0; q->right = x;
   1.309 +            if (x != NULL) x->up = q, x->flag = 1;
   1.310 +            if (y != NULL) y->up = p, y->flag = 0;
   1.311 +            node = r;
   1.312 +         }
   1.313 +      }
   1.314 +      else
   1.315 +      {  /* perform positive (right) rotation */
   1.316 +         f = p->up; q = p->right; r = q->left;
   1.317 +         if (q->bal >= 0)
   1.318 +         {  /* perform single positive rotation */
   1.319 +            if (f == NULL)
   1.320 +               tree->root = q;
   1.321 +            else
   1.322 +               if (p->flag == 0) f->left = q; else f->right = q;
   1.323 +            q->rank += p->rank;
   1.324 +            q->up = f; q->flag = p->flag; q->bal--; q->left = p;
   1.325 +            p->up = q; p->flag = 0;
   1.326 +            p->bal = (short int)(-q->bal); p->right = r;
   1.327 +            if (r != NULL) r->up = p, r->flag = 1;
   1.328 +            node = q;
   1.329 +         }
   1.330 +         else
   1.331 +         {  /* perform double positive rotation */
   1.332 +            x = r->left; y = r->right;
   1.333 +            if (f == NULL)
   1.334 +               tree->root = r;
   1.335 +            else
   1.336 +               if (p->flag == 0) f->left = r; else f->right = r;
   1.337 +            q->rank -= r->rank;
   1.338 +            r->rank += p->rank;
   1.339 +            p->bal = (short int)(r->bal <= 0 ? 0 : -1);
   1.340 +            q->bal = (short int)(r->bal >= 0 ? 0 : +1);
   1.341 +            r->up = f; r->flag = p->flag; r->bal = 0;
   1.342 +            r->left = p; r->right = q;
   1.343 +            p->up = r; p->flag = 0; p->right = x;
   1.344 +            q->up = r; q->flag = 1; q->left = y;
   1.345 +            if (x != NULL) x->up = p, x->flag = 1;
   1.346 +            if (y != NULL) y->up = q, y->flag = 0;
   1.347 +            node = r;
   1.348 +         }
   1.349 +      }
   1.350 +      return node;
   1.351 +}
   1.352 +
   1.353 +void avl_delete_tree(AVL *tree)
   1.354 +{     /* delete AVL tree */
   1.355 +      dmp_delete_pool(tree->pool);
   1.356 +      xfree(tree);
   1.357 +      return;
   1.358 +}
   1.359 +
   1.360 +/* eof */