123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- /* glpavl.c (binary search tree) */
- /***********************************************************************
- * This code is part of GLPK (GNU Linear Programming Kit).
- *
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
- * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
- * E-mail: <mao@gnu.org>.
- *
- * GLPK is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GLPK is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
- ***********************************************************************/
- #include "glpavl.h"
- AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
- const void *key2), void *info)
- { /* create AVL tree */
- AVL *tree;
- tree = xmalloc(sizeof(AVL));
- tree->pool = dmp_create_pool();
- tree->root = NULL;
- tree->fcmp = fcmp;
- tree->info = info;
- tree->size = 0;
- tree->height = 0;
- return tree;
- }
- int avl_strcmp(void *info, const void *key1, const void *key2)
- { /* compare character string keys */
- xassert(info == info);
- return strcmp(key1, key2);
- }
- static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node);
- AVLNODE *avl_insert_node(AVL *tree, const void *key)
- { /* insert new node into AVL tree */
- AVLNODE *p, *q, *r;
- short int flag;
- /* find an appropriate point for insertion */
- p = NULL; q = tree->root;
- while (q != NULL)
- { p = q;
- if (tree->fcmp(tree->info, key, p->key) <= 0)
- { flag = 0;
- q = p->left;
- p->rank++;
- }
- else
- { flag = 1;
- q = p->right;
- }
- }
- /* create new node and insert it into the tree */
- r = dmp_get_atom(tree->pool, sizeof(AVLNODE));
- r->key = key; r->type = 0; r->link = NULL;
- r->rank = 1; r->up = p;
- r->flag = (short int)(p == NULL ? 0 : flag);
- r->bal = 0; r->left = NULL; r->right = NULL;
- tree->size++;
- if (p == NULL)
- tree->root = r;
- else
- if (flag == 0) p->left = r; else p->right = r;
- /* go upstairs to the root and correct all subtrees affected by
- insertion */
- while (p != NULL)
- { if (flag == 0)
- { /* the height of the left subtree of [p] is increased */
- if (p->bal > 0)
- { p->bal = 0;
- break;
- }
- if (p->bal < 0)
- { rotate_subtree(tree, p);
- break;
- }
- p->bal = -1; flag = p->flag; p = p->up;
- }
- else
- { /* the height of the right subtree of [p] is increased */
- if (p->bal < 0)
- { p->bal = 0;
- break;
- }
- if (p->bal > 0)
- { rotate_subtree(tree, p);
- break;
- }
- p->bal = +1; flag = p->flag; p = p->up;
- }
- }
- /* if the root has been reached, the height of the entire tree is
- increased */
- if (p == NULL) tree->height++;
- return r;
- }
- void avl_set_node_type(AVLNODE *node, int type)
- { /* assign the type field of specified node */
- node->type = type;
- return;
- }
- void avl_set_node_link(AVLNODE *node, void *link)
- { /* assign the link field of specified node */
- node->link = link;
- return;
- }
- AVLNODE *avl_find_node(AVL *tree, const void *key)
- { /* find node in AVL tree */
- AVLNODE *p;
- int c;
- p = tree->root;
- while (p != NULL)
- { c = tree->fcmp(tree->info, key, p->key);
- if (c == 0) break;
- p = (c < 0 ? p->left : p->right);
- }
- return p;
- }
- int avl_get_node_type(AVLNODE *node)
- { /* retrieve the type field of specified node */
- return node->type;
- }
- void *avl_get_node_link(AVLNODE *node)
- { /* retrieve the link field of specified node */
- return node->link;
- }
- static AVLNODE *find_next_node(AVL *tree, AVLNODE *node)
- { /* find next node in AVL tree */
- AVLNODE *p, *q;
- if (tree->root == NULL) return NULL;
- p = node;
- q = (p == NULL ? tree->root : p->right);
- if (q == NULL)
- { /* go upstairs from the left subtree */
- for (;;)
- { q = p->up;
- if (q == NULL) break;
- if (p->flag == 0) break;
- p = q;
- }
- }
- else
- { /* go downstairs into the right subtree */
- for (;;)
- { p = q->left;
- if (p == NULL) break;
- q = p;
- }
- }
- return q;
- }
- void avl_delete_node(AVL *tree, AVLNODE *node)
- { /* delete specified node from AVL tree */
- AVLNODE *f, *p, *q, *r, *s, *x, *y;
- short int flag;
- p = node;
- /* if both subtrees of the specified node are non-empty, the node
- should be interchanged with the next one, at least one subtree
- of which is always empty */
- if (p->left == NULL || p->right == NULL) goto skip;
- f = p->up; q = p->left;
- r = find_next_node(tree, p); s = r->right;
- if (p->right == r)
- { if (f == NULL)
- tree->root = r;
- else
- if (p->flag == 0) f->left = r; else f->right = r;
- r->rank = p->rank; r->up = f;
- r->flag = p->flag; r->bal = p->bal;
- r->left = q; r->right = p;
- q->up = r;
- p->rank = 1; p->up = r; p->flag = 1;
- p->bal = (short int)(s == NULL ? 0 : +1);
- p->left = NULL; p->right = s;
- if (s != NULL) s->up = p;
- }
- else
- { x = p->right; y = r->up;
- if (f == NULL)
- tree->root = r;
- else
- if (p->flag == 0) f->left = r; else f->right = r;
- r->rank = p->rank; r->up = f;
- r->flag = p->flag; r->bal = p->bal;
- r->left = q; r->right = x;
- q->up = r; x->up = r; y->left = p;
- p->rank = 1; p->up = y; p->flag = 0;
- p->bal = (short int)(s == NULL ? 0 : +1);
- p->left = NULL; p->right = s;
- if (s != NULL) s->up = p;
- }
- skip: /* now the specified node [p] has at least one empty subtree;
- go upstairs to the root and adjust the rank field of all nodes
- affected by deletion */
- q = p; f = q->up;
- while (f != NULL)
- { if (q->flag == 0) f->rank--;
- q = f; f = q->up;
- }
- /* delete the specified node from the tree */
- f = p->up; flag = p->flag;
- q = p->left != NULL ? p->left : p->right;
- if (f == NULL)
- tree->root = q;
- else
- if (flag == 0) f->left = q; else f->right = q;
- if (q != NULL) q->up = f, q->flag = flag;
- tree->size--;
- /* go upstairs to the root and correct all subtrees affected by
- deletion */
- while (f != NULL)
- { if (flag == 0)
- { /* the height of the left subtree of [f] is decreased */
- if (f->bal == 0)
- { f->bal = +1;
- break;
- }
- if (f->bal < 0)
- f->bal = 0;
- else
- { f = rotate_subtree(tree, f);
- if (f->bal < 0) break;
- }
- flag = f->flag; f = f->up;
- }
- else
- { /* the height of the right subtree of [f] is decreased */
- if (f->bal == 0)
- { f->bal = -1;
- break;
- }
- if (f->bal > 0)
- f->bal = 0;
- else
- { f = rotate_subtree(tree, f);
- if (f->bal > 0) break;
- }
- flag = f->flag; f = f->up;
- }
- }
- /* if the root has been reached, the height of the entire tree is
- decreased */
- if (f == NULL) tree->height--;
- /* returns the deleted node to the memory pool */
- dmp_free_atom(tree->pool, p, sizeof(AVLNODE));
- return;
- }
- static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node)
- { /* restore balance of AVL subtree */
- AVLNODE *f, *p, *q, *r, *x, *y;
- xassert(node != NULL);
- p = node;
- if (p->bal < 0)
- { /* perform negative (left) rotation */
- f = p->up; q = p->left; r = q->right;
- if (q->bal <= 0)
- { /* perform single negative rotation */
- if (f == NULL)
- tree->root = q;
- else
- if (p->flag == 0) f->left = q; else f->right = q;
- p->rank -= q->rank;
- q->up = f; q->flag = p->flag; q->bal++; q->right = p;
- p->up = q; p->flag = 1;
- p->bal = (short int)(-q->bal); p->left = r;
- if (r != NULL) r->up = p, r->flag = 0;
- node = q;
- }
- else
- { /* perform double negative rotation */
- x = r->left; y = r->right;
- if (f == NULL)
- tree->root = r;
- else
- if (p->flag == 0) f->left = r; else f->right = r;
- p->rank -= (q->rank + r->rank);
- r->rank += q->rank;
- p->bal = (short int)(r->bal >= 0 ? 0 : +1);
- q->bal = (short int)(r->bal <= 0 ? 0 : -1);
- r->up = f; r->flag = p->flag; r->bal = 0;
- r->left = q; r->right = p;
- p->up = r; p->flag = 1; p->left = y;
- q->up = r; q->flag = 0; q->right = x;
- if (x != NULL) x->up = q, x->flag = 1;
- if (y != NULL) y->up = p, y->flag = 0;
- node = r;
- }
- }
- else
- { /* perform positive (right) rotation */
- f = p->up; q = p->right; r = q->left;
- if (q->bal >= 0)
- { /* perform single positive rotation */
- if (f == NULL)
- tree->root = q;
- else
- if (p->flag == 0) f->left = q; else f->right = q;
- q->rank += p->rank;
- q->up = f; q->flag = p->flag; q->bal--; q->left = p;
- p->up = q; p->flag = 0;
- p->bal = (short int)(-q->bal); p->right = r;
- if (r != NULL) r->up = p, r->flag = 1;
- node = q;
- }
- else
- { /* perform double positive rotation */
- x = r->left; y = r->right;
- if (f == NULL)
- tree->root = r;
- else
- if (p->flag == 0) f->left = r; else f->right = r;
- q->rank -= r->rank;
- r->rank += p->rank;
- p->bal = (short int)(r->bal <= 0 ? 0 : -1);
- q->bal = (short int)(r->bal >= 0 ? 0 : +1);
- r->up = f; r->flag = p->flag; r->bal = 0;
- r->left = p; r->right = q;
- p->up = r; p->flag = 0; p->right = x;
- q->up = r; q->flag = 1; q->left = y;
- if (x != NULL) x->up = p, x->flag = 1;
- if (y != NULL) y->up = q, y->flag = 0;
- node = r;
- }
- }
- return node;
- }
- void avl_delete_tree(AVL *tree)
- { /* delete AVL tree */
- dmp_delete_pool(tree->pool);
- xfree(tree);
- return;
- }
- /* eof */
|