src/glpavl.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
alpar@1
     1
/* glpavl.c (binary search tree) */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#include "glpavl.h"
alpar@1
    26
alpar@1
    27
AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
alpar@1
    28
      const void *key2), void *info)
alpar@1
    29
{     /* create AVL tree */
alpar@1
    30
      AVL *tree;
alpar@1
    31
      tree = xmalloc(sizeof(AVL));
alpar@1
    32
      tree->pool = dmp_create_pool();
alpar@1
    33
      tree->root = NULL;
alpar@1
    34
      tree->fcmp = fcmp;
alpar@1
    35
      tree->info = info;
alpar@1
    36
      tree->size = 0;
alpar@1
    37
      tree->height = 0;
alpar@1
    38
      return tree;
alpar@1
    39
}
alpar@1
    40
alpar@1
    41
int avl_strcmp(void *info, const void *key1, const void *key2)
alpar@1
    42
{     /* compare character string keys */
alpar@1
    43
      xassert(info == info);
alpar@1
    44
      return strcmp(key1, key2);
alpar@1
    45
}
alpar@1
    46
alpar@1
    47
static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node);
alpar@1
    48
alpar@1
    49
AVLNODE *avl_insert_node(AVL *tree, const void *key)
alpar@1
    50
{     /* insert new node into AVL tree */
alpar@1
    51
      AVLNODE *p, *q, *r;
alpar@1
    52
      short int flag;
alpar@1
    53
      /* find an appropriate point for insertion */
alpar@1
    54
      p = NULL; q = tree->root;
alpar@1
    55
      while (q != NULL)
alpar@1
    56
      {  p = q;
alpar@1
    57
         if (tree->fcmp(tree->info, key, p->key) <= 0)
alpar@1
    58
         {  flag = 0;
alpar@1
    59
            q = p->left;
alpar@1
    60
            p->rank++;
alpar@1
    61
         }
alpar@1
    62
         else
alpar@1
    63
         {  flag = 1;
alpar@1
    64
            q = p->right;
alpar@1
    65
         }
alpar@1
    66
      }
alpar@1
    67
      /* create new node and insert it into the tree */
alpar@1
    68
      r = dmp_get_atom(tree->pool, sizeof(AVLNODE));
alpar@1
    69
      r->key = key; r->type = 0; r->link = NULL;
alpar@1
    70
      r->rank = 1; r->up = p;
alpar@1
    71
      r->flag = (short int)(p == NULL ? 0 : flag);
alpar@1
    72
      r->bal = 0; r->left = NULL; r->right = NULL;
alpar@1
    73
      tree->size++;
alpar@1
    74
      if (p == NULL)
alpar@1
    75
         tree->root = r;
alpar@1
    76
      else
alpar@1
    77
         if (flag == 0) p->left = r; else p->right = r;
alpar@1
    78
      /* go upstairs to the root and correct all subtrees affected by
alpar@1
    79
         insertion */
alpar@1
    80
      while (p != NULL)
alpar@1
    81
      {  if (flag == 0)
alpar@1
    82
         {  /* the height of the left subtree of [p] is increased */
alpar@1
    83
            if (p->bal > 0)
alpar@1
    84
            {  p->bal = 0;
alpar@1
    85
               break;
alpar@1
    86
            }
alpar@1
    87
            if (p->bal < 0)
alpar@1
    88
            {  rotate_subtree(tree, p);
alpar@1
    89
               break;
alpar@1
    90
            }
alpar@1
    91
            p->bal = -1; flag = p->flag; p = p->up;
alpar@1
    92
         }
alpar@1
    93
         else
alpar@1
    94
         {  /* the height of the right subtree of [p] is increased */
alpar@1
    95
            if (p->bal < 0)
alpar@1
    96
            {  p->bal = 0;
alpar@1
    97
               break;
alpar@1
    98
            }
alpar@1
    99
            if (p->bal > 0)
alpar@1
   100
            {  rotate_subtree(tree, p);
alpar@1
   101
               break;
alpar@1
   102
            }
alpar@1
   103
            p->bal = +1; flag = p->flag; p = p->up;
alpar@1
   104
         }
alpar@1
   105
      }
alpar@1
   106
      /* if the root has been reached, the height of the entire tree is
alpar@1
   107
         increased */
alpar@1
   108
      if (p == NULL) tree->height++;
alpar@1
   109
      return r;
alpar@1
   110
}
alpar@1
   111
alpar@1
   112
void avl_set_node_type(AVLNODE *node, int type)
alpar@1
   113
{     /* assign the type field of specified node */
alpar@1
   114
      node->type = type;
alpar@1
   115
      return;
alpar@1
   116
}
alpar@1
   117
alpar@1
   118
void avl_set_node_link(AVLNODE *node, void *link)
alpar@1
   119
{     /* assign the link field of specified node */
alpar@1
   120
      node->link = link;
alpar@1
   121
      return;
alpar@1
   122
}
alpar@1
   123
alpar@1
   124
AVLNODE *avl_find_node(AVL *tree, const void *key)
alpar@1
   125
{     /* find node in AVL tree */
alpar@1
   126
      AVLNODE *p;
alpar@1
   127
      int c;
alpar@1
   128
      p = tree->root;
alpar@1
   129
      while (p != NULL)
alpar@1
   130
      {  c = tree->fcmp(tree->info, key, p->key);
alpar@1
   131
         if (c == 0) break;
alpar@1
   132
         p = (c < 0 ? p->left : p->right);
alpar@1
   133
      }
alpar@1
   134
      return p;
alpar@1
   135
}
alpar@1
   136
alpar@1
   137
int avl_get_node_type(AVLNODE *node)
alpar@1
   138
{     /* retrieve the type field of specified node */
alpar@1
   139
      return node->type;
alpar@1
   140
}
alpar@1
   141
alpar@1
   142
void *avl_get_node_link(AVLNODE *node)
alpar@1
   143
{     /* retrieve the link field of specified node */
alpar@1
   144
      return node->link;
alpar@1
   145
}
alpar@1
   146
alpar@1
   147
static AVLNODE *find_next_node(AVL *tree, AVLNODE *node)
alpar@1
   148
{     /* find next node in AVL tree */
alpar@1
   149
      AVLNODE *p, *q;
alpar@1
   150
      if (tree->root == NULL) return NULL;
alpar@1
   151
      p = node;
alpar@1
   152
      q = (p == NULL ? tree->root : p->right);
alpar@1
   153
      if (q == NULL)
alpar@1
   154
      {  /* go upstairs from the left subtree */
alpar@1
   155
         for (;;)
alpar@1
   156
         {  q = p->up;
alpar@1
   157
            if (q == NULL) break;
alpar@1
   158
            if (p->flag == 0) break;
alpar@1
   159
            p = q;
alpar@1
   160
         }
alpar@1
   161
      }
alpar@1
   162
      else
alpar@1
   163
      {  /* go downstairs into the right subtree */
alpar@1
   164
         for (;;)
alpar@1
   165
         {  p = q->left;
alpar@1
   166
            if (p == NULL) break;
alpar@1
   167
            q = p;
alpar@1
   168
         }
alpar@1
   169
      }
alpar@1
   170
      return q;
alpar@1
   171
}
alpar@1
   172
alpar@1
   173
void avl_delete_node(AVL *tree, AVLNODE *node)
alpar@1
   174
{     /* delete specified node from AVL tree */
alpar@1
   175
      AVLNODE *f, *p, *q, *r, *s, *x, *y;
alpar@1
   176
      short int flag;
alpar@1
   177
      p = node;
alpar@1
   178
      /* if both subtrees of the specified node are non-empty, the node
alpar@1
   179
         should be interchanged with the next one, at least one subtree
alpar@1
   180
         of which is always empty */
alpar@1
   181
      if (p->left == NULL || p->right == NULL) goto skip;
alpar@1
   182
      f = p->up; q = p->left;
alpar@1
   183
      r = find_next_node(tree, p); s = r->right;
alpar@1
   184
      if (p->right == r)
alpar@1
   185
      {  if (f == NULL)
alpar@1
   186
            tree->root = r;
alpar@1
   187
         else
alpar@1
   188
            if (p->flag == 0) f->left = r; else f->right = r;
alpar@1
   189
         r->rank = p->rank; r->up = f;
alpar@1
   190
         r->flag = p->flag; r->bal = p->bal;
alpar@1
   191
         r->left = q; r->right = p;
alpar@1
   192
         q->up = r;
alpar@1
   193
         p->rank = 1; p->up = r; p->flag = 1;
alpar@1
   194
         p->bal = (short int)(s == NULL ? 0 : +1);
alpar@1
   195
         p->left = NULL; p->right = s;
alpar@1
   196
         if (s != NULL) s->up = p;
alpar@1
   197
      }
alpar@1
   198
      else
alpar@1
   199
      {  x = p->right; y = r->up;
alpar@1
   200
         if (f == NULL)
alpar@1
   201
            tree->root = r;
alpar@1
   202
         else
alpar@1
   203
            if (p->flag == 0) f->left = r; else f->right = r;
alpar@1
   204
         r->rank = p->rank; r->up = f;
alpar@1
   205
         r->flag = p->flag; r->bal = p->bal;
alpar@1
   206
         r->left = q; r->right = x;
alpar@1
   207
         q->up = r; x->up = r; y->left = p;
alpar@1
   208
         p->rank = 1; p->up = y; p->flag = 0;
alpar@1
   209
         p->bal = (short int)(s == NULL ? 0 : +1);
alpar@1
   210
         p->left = NULL; p->right = s;
alpar@1
   211
         if (s != NULL) s->up = p;
alpar@1
   212
      }
alpar@1
   213
skip: /* now the specified node [p] has at least one empty subtree;
alpar@1
   214
         go upstairs to the root and adjust the rank field of all nodes
alpar@1
   215
         affected by deletion */
alpar@1
   216
      q = p; f = q->up;
alpar@1
   217
      while (f != NULL)
alpar@1
   218
      {  if (q->flag == 0) f->rank--;
alpar@1
   219
         q = f; f = q->up;
alpar@1
   220
      }
alpar@1
   221
      /* delete the specified node from the tree */
alpar@1
   222
      f = p->up; flag = p->flag;
alpar@1
   223
      q = p->left != NULL ? p->left : p->right;
alpar@1
   224
      if (f == NULL)
alpar@1
   225
         tree->root = q;
alpar@1
   226
      else
alpar@1
   227
         if (flag == 0) f->left = q; else f->right = q;
alpar@1
   228
      if (q != NULL) q->up = f, q->flag = flag;
alpar@1
   229
      tree->size--;
alpar@1
   230
      /* go upstairs to the root and correct all subtrees affected by
alpar@1
   231
         deletion */
alpar@1
   232
      while (f != NULL)
alpar@1
   233
      {  if (flag == 0)
alpar@1
   234
         {  /* the height of the left subtree of [f] is decreased */
alpar@1
   235
            if (f->bal == 0)
alpar@1
   236
            {  f->bal = +1;
alpar@1
   237
               break;
alpar@1
   238
            }
alpar@1
   239
            if (f->bal < 0)
alpar@1
   240
               f->bal = 0;
alpar@1
   241
            else
alpar@1
   242
            {  f = rotate_subtree(tree, f);
alpar@1
   243
               if (f->bal < 0) break;
alpar@1
   244
            }
alpar@1
   245
            flag = f->flag; f = f->up;
alpar@1
   246
         }
alpar@1
   247
         else
alpar@1
   248
         {  /* the height of the right subtree of [f] is decreased */
alpar@1
   249
            if (f->bal == 0)
alpar@1
   250
            {  f->bal = -1;
alpar@1
   251
               break;
alpar@1
   252
            }
alpar@1
   253
            if (f->bal > 0)
alpar@1
   254
               f->bal = 0;
alpar@1
   255
            else
alpar@1
   256
            {  f = rotate_subtree(tree, f);
alpar@1
   257
               if (f->bal > 0) break;
alpar@1
   258
            }
alpar@1
   259
            flag = f->flag; f = f->up;
alpar@1
   260
         }
alpar@1
   261
      }
alpar@1
   262
      /* if the root has been reached, the height of the entire tree is
alpar@1
   263
         decreased */
alpar@1
   264
      if (f == NULL) tree->height--;
alpar@1
   265
      /* returns the deleted node to the memory pool */
alpar@1
   266
      dmp_free_atom(tree->pool, p, sizeof(AVLNODE));
alpar@1
   267
      return;
alpar@1
   268
}
alpar@1
   269
alpar@1
   270
static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node)
alpar@1
   271
{     /* restore balance of AVL subtree */
alpar@1
   272
      AVLNODE *f, *p, *q, *r, *x, *y;
alpar@1
   273
      xassert(node != NULL);
alpar@1
   274
      p = node;
alpar@1
   275
      if (p->bal < 0)
alpar@1
   276
      {  /* perform negative (left) rotation */
alpar@1
   277
         f = p->up; q = p->left; r = q->right;
alpar@1
   278
         if (q->bal <= 0)
alpar@1
   279
         {  /* perform single negative rotation */
alpar@1
   280
            if (f == NULL)
alpar@1
   281
               tree->root = q;
alpar@1
   282
            else
alpar@1
   283
               if (p->flag == 0) f->left = q; else f->right = q;
alpar@1
   284
            p->rank -= q->rank;
alpar@1
   285
            q->up = f; q->flag = p->flag; q->bal++; q->right = p;
alpar@1
   286
            p->up = q; p->flag = 1;
alpar@1
   287
            p->bal = (short int)(-q->bal); p->left = r;
alpar@1
   288
            if (r != NULL) r->up = p, r->flag = 0;
alpar@1
   289
            node = q;
alpar@1
   290
         }
alpar@1
   291
         else
alpar@1
   292
         {  /* perform double negative rotation */
alpar@1
   293
            x = r->left; y = r->right;
alpar@1
   294
            if (f == NULL)
alpar@1
   295
               tree->root = r;
alpar@1
   296
            else
alpar@1
   297
               if (p->flag == 0) f->left = r; else f->right = r;
alpar@1
   298
            p->rank -= (q->rank + r->rank);
alpar@1
   299
            r->rank += q->rank;
alpar@1
   300
            p->bal = (short int)(r->bal >= 0 ? 0 : +1);
alpar@1
   301
            q->bal = (short int)(r->bal <= 0 ? 0 : -1);
alpar@1
   302
            r->up = f; r->flag = p->flag; r->bal = 0;
alpar@1
   303
            r->left = q; r->right = p;
alpar@1
   304
            p->up = r; p->flag = 1; p->left = y;
alpar@1
   305
            q->up = r; q->flag = 0; q->right = x;
alpar@1
   306
            if (x != NULL) x->up = q, x->flag = 1;
alpar@1
   307
            if (y != NULL) y->up = p, y->flag = 0;
alpar@1
   308
            node = r;
alpar@1
   309
         }
alpar@1
   310
      }
alpar@1
   311
      else
alpar@1
   312
      {  /* perform positive (right) rotation */
alpar@1
   313
         f = p->up; q = p->right; r = q->left;
alpar@1
   314
         if (q->bal >= 0)
alpar@1
   315
         {  /* perform single positive rotation */
alpar@1
   316
            if (f == NULL)
alpar@1
   317
               tree->root = q;
alpar@1
   318
            else
alpar@1
   319
               if (p->flag == 0) f->left = q; else f->right = q;
alpar@1
   320
            q->rank += p->rank;
alpar@1
   321
            q->up = f; q->flag = p->flag; q->bal--; q->left = p;
alpar@1
   322
            p->up = q; p->flag = 0;
alpar@1
   323
            p->bal = (short int)(-q->bal); p->right = r;
alpar@1
   324
            if (r != NULL) r->up = p, r->flag = 1;
alpar@1
   325
            node = q;
alpar@1
   326
         }
alpar@1
   327
         else
alpar@1
   328
         {  /* perform double positive rotation */
alpar@1
   329
            x = r->left; y = r->right;
alpar@1
   330
            if (f == NULL)
alpar@1
   331
               tree->root = r;
alpar@1
   332
            else
alpar@1
   333
               if (p->flag == 0) f->left = r; else f->right = r;
alpar@1
   334
            q->rank -= r->rank;
alpar@1
   335
            r->rank += p->rank;
alpar@1
   336
            p->bal = (short int)(r->bal <= 0 ? 0 : -1);
alpar@1
   337
            q->bal = (short int)(r->bal >= 0 ? 0 : +1);
alpar@1
   338
            r->up = f; r->flag = p->flag; r->bal = 0;
alpar@1
   339
            r->left = p; r->right = q;
alpar@1
   340
            p->up = r; p->flag = 0; p->right = x;
alpar@1
   341
            q->up = r; q->flag = 1; q->left = y;
alpar@1
   342
            if (x != NULL) x->up = p, x->flag = 1;
alpar@1
   343
            if (y != NULL) y->up = q, y->flag = 0;
alpar@1
   344
            node = r;
alpar@1
   345
         }
alpar@1
   346
      }
alpar@1
   347
      return node;
alpar@1
   348
}
alpar@1
   349
alpar@1
   350
void avl_delete_tree(AVL *tree)
alpar@1
   351
{     /* delete AVL tree */
alpar@1
   352
      dmp_delete_pool(tree->pool);
alpar@1
   353
      xfree(tree);
alpar@1
   354
      return;
alpar@1
   355
}
alpar@1
   356
alpar@1
   357
/* eof */