rb_insert.c

Go to the documentation of this file.
00001 /*                     R B _ I N S E R T . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1998-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup rb */
00023 /*@{*/
00024 /** @file rb_insert.c
00025  *              Routines to insert into a red-black tree
00026  *
00027  *  @author
00028  *      Paul J. Tanenbaum
00029  *
00030  * @par Source -
00031  *      The U. S. Army Research Laboratory
00032  *@n    Aberdeen Proving Ground, Maryland  21005-5068  USA
00033  */
00034 
00035 #ifndef lint
00036 static const char libbu_rb_insert_RCSid[] = "@(#) $Header: /cvsroot/brlcad/brlcad/src/libbu/rb_insert.c,v 14.13 2006/08/31 23:16:38 lbutler Exp $";
00037 #endif
00038 
00039 #include "common.h"
00040 
00041 #include <stdlib.h>
00042 #include <stdio.h>
00043 #include <math.h>
00044 
00045 #include "machine.h"
00046 #include "bu.h"
00047 #include "./rb_internals.h"
00048 
00049 
00050 /**                     _ R B _ I N S E R T ( )
00051  *
00052  *          Insert a node into one linear order of a red-black tree
00053  *
00054  *      This function has three parameters: the tree and linear order into
00055  *      which to insert the new node and the new node itself.  If the node
00056  *      is equal (modulo the linear order) to a node already in the tree,
00057  *      _rb_insert() returns 1.  Otherwise, it returns 0.
00058  */
00059 static int _rb_insert (bu_rb_tree *tree, int order, struct bu_rb_node *new_node)
00060 {
00061     struct bu_rb_node   *node;
00062     struct bu_rb_node   *parent;
00063     struct bu_rb_node   *grand_parent;
00064     struct bu_rb_node   *y;
00065     int                 (*compare)();
00066     int                 comparison=0xdeadbeef;
00067     int                 direction;
00068     int                 result = 0;
00069 
00070 
00071     BU_CKMAG(tree, BU_RB_TREE_MAGIC, "red-black tree");
00072     BU_RB_CKORDER(tree, order);
00073     BU_CKMAG(new_node, BU_RB_NODE_MAGIC, "red-black node");
00074 
00075     /*
00076      *  Initialize the new node
00077      */
00078     bu_rb_parent(new_node, order) =
00079     bu_rb_left_child(new_node, order) =
00080     bu_rb_right_child(new_node, order) = bu_rb_null(tree);
00081     bu_rb_size(new_node, order) = 1;
00082     if (tree -> rbt_debug & BU_RB_DEBUG_OS)
00083         bu_log("_rb_insert(%x): size(%x, %d)=%d\n",
00084             new_node, new_node, order, bu_rb_size(new_node, order));
00085 
00086     /*
00087      *  Perform vanilla-flavored binary-tree insertion
00088      */
00089     parent = bu_rb_null(tree);
00090     node = bu_rb_root(tree, order);
00091     compare = bu_rb_order_func(tree, order);
00092     while (node != bu_rb_null(tree))
00093     {
00094         parent = node;
00095         ++bu_rb_size(parent, order);
00096         if (tree -> rbt_debug & BU_RB_DEBUG_OS)
00097             bu_log("_rb_insert(%x): size(%x, %d)=%d\n",
00098                 new_node, parent, order, bu_rb_size(parent, order));
00099         comparison = (*compare)(bu_rb_data(new_node, order),
00100                                 bu_rb_data(node, order));
00101         if (comparison < 0)
00102         {
00103             if (tree -> rbt_debug & BU_RB_DEBUG_INSERT)
00104                 bu_log("_rb_insert(%x): <_%d <%x>, going left\n",
00105                     new_node, order, node);
00106             node = bu_rb_left_child(node, order);
00107         }
00108         else
00109         {
00110             if (tree -> rbt_debug & BU_RB_DEBUG_INSERT)
00111                 bu_log("_rb_insert(%x): >=_%d <%x>, going right\n",
00112                     new_node, order, node);
00113             node = bu_rb_right_child(node, order);
00114             if (comparison == 0)
00115                 result = 1;
00116         }
00117     }
00118     bu_rb_parent(new_node, order) = parent;
00119     if (parent == bu_rb_null(tree))
00120         bu_rb_root(tree, order) = new_node;
00121     else if ((*compare)(bu_rb_data(new_node, order),
00122                         bu_rb_data(parent, order)) < 0)
00123         bu_rb_left_child(parent, order) = new_node;
00124     else
00125         bu_rb_right_child(parent, order) = new_node;
00126 
00127     /*
00128      *  Reestablish the red-black properties, as necessary
00129      */
00130     bu_rb_set_color(new_node, order, BU_RB_RED);
00131     node = new_node;
00132     parent = bu_rb_parent(node, order);
00133     grand_parent = bu_rb_parent(parent, order);
00134     while ((node != bu_rb_root(tree, order))
00135         && (bu_rb_get_color(parent, order) == BU_RB_RED))
00136     {
00137         if (parent == bu_rb_left_child(grand_parent, order))
00138             direction = BU_RB_LEFT;
00139         else
00140             direction = BU_RB_RIGHT;
00141 
00142         y = bu_rb_other_child(grand_parent, order, direction);
00143         if (bu_rb_get_color(y, order) == BU_RB_RED)
00144         {
00145             bu_rb_set_color(parent, order, BU_RB_BLACK);
00146             bu_rb_set_color(y, order, BU_RB_BLACK);
00147             bu_rb_set_color(grand_parent, order, BU_RB_RED);
00148             node = grand_parent;
00149             parent = bu_rb_parent(node, order);
00150             grand_parent = bu_rb_parent(parent, order);
00151         }
00152         else
00153         {
00154             if (node == bu_rb_other_child(parent, order, direction))
00155             {
00156                 node = parent;
00157                 bu_rb_rotate(node, order, direction);
00158                 parent = bu_rb_parent(node, order);
00159                 grand_parent = bu_rb_parent(parent, order);
00160             }
00161             bu_rb_set_color(parent, order, BU_RB_BLACK);
00162             bu_rb_set_color(grand_parent, order, BU_RB_RED);
00163             bu_rb_other_rotate(grand_parent, order, direction);
00164         }
00165     }
00166     bu_rb_set_color(bu_rb_root(tree, order), order, BU_RB_BLACK);
00167 
00168     if (tree -> rbt_debug & BU_RB_DEBUG_INSERT)
00169         bu_log("_rb_insert(%x): comparison = %d, returning %d\n",
00170             new_node, comparison, result);
00171 
00172     return (result);
00173 }
00174 
00175 /**                     B U _ R B _ I N S E R T ( )
00176  *
00177  *              Applications interface to _rb_insert()
00178  *
00179  *      This function has two parameters: the tree into which to insert
00180  *      the new node and the contents of the node.  If a uniqueness
00181  *      requirement would be violated, bu_rb_insert() does nothing but return
00182  *      a number from the set {-1, -2, ..., -nm_orders} of which the
00183  *      absolute value is the first order for which a violation exists.
00184  *      Otherwise, it returns the number of orders for which the new node
00185  *      was equal to a node already in the tree.
00186  */
00187 int bu_rb_insert (bu_rb_tree *tree, void *data)
00188 {
00189     int                         nm_orders;
00190     int                         order;
00191     int                         result = 0;
00192     struct bu_rb_node           *node;
00193     struct bu_rb_package        *package;
00194     struct bu_rb_list           *rblp;
00195 
00196     BU_CKMAG(tree, BU_RB_TREE_MAGIC, "red-black tree");
00197 
00198     nm_orders = tree -> rbt_nm_orders;
00199 
00200     /*
00201      *  Enforce uniqueness
00202      *
00203      *  NOTE: The approach is that for each order that requires uniqueness,
00204      *      we look for a match.  This is not the most efficient way to do
00205      *      things, since _rb_insert() is just going to turn around and
00206      *      search the tree all over again.
00207      */
00208     for (order = 0; order < nm_orders; ++order)
00209         if (bu_rb_get_uniqueness(tree, order) &&
00210             (bu_rb_search(tree, order, data) != NULL))
00211         {
00212             if (tree -> rbt_debug & BU_RB_DEBUG_UNIQ)
00213                 bu_log("bu_rb_insert(<%x>, <%x>, TBD) will return %d\n",
00214                     tree, data, -(order + 1));
00215             return (-(order + 1));
00216         }
00217 
00218     /*
00219      *  Make a new package
00220      *  and add it to the list of all packages.
00221      */
00222     package = (struct bu_rb_package *)
00223                 bu_malloc(sizeof(struct bu_rb_package), "red-black package");
00224     package -> rbp_node = (struct bu_rb_node **)
00225                 bu_malloc(nm_orders * sizeof(struct bu_rb_node *),
00226                             "red-black package nodes");
00227     rblp = (struct bu_rb_list *)
00228                 bu_malloc(sizeof(struct bu_rb_list),
00229                             "red-black list element");
00230     rblp -> rbl_magic = BU_RB_LIST_MAGIC;
00231     rblp -> rbl_package = package;
00232     BU_LIST_PUSH(&(tree -> rbt_packages.l), rblp);
00233     package -> rbp_list_pos = rblp;
00234 
00235     /*
00236      *  Make a new node
00237      *  and add it to the list of all nodes.
00238      */
00239     node = (struct bu_rb_node *)
00240                 bu_malloc(sizeof(struct bu_rb_node), "red-black node");
00241     node -> rbn_parent = (struct bu_rb_node **)
00242                 bu_malloc(nm_orders * sizeof(struct bu_rb_node *),
00243                             "red-black parents");
00244     node -> rbn_left = (struct bu_rb_node **)
00245                 bu_malloc(nm_orders * sizeof(struct bu_rb_node *),
00246                             "red-black left children");
00247     node -> rbn_right = (struct bu_rb_node **)
00248                 bu_malloc(nm_orders * sizeof(struct bu_rb_node *),
00249                             "red-black right children");
00250     node -> rbn_color = (char *)
00251                 bu_malloc((size_t) ceil((double) (nm_orders / 8.0)),
00252                             "red-black colors");
00253     node -> rbn_size = (int *)
00254                 bu_malloc(nm_orders * sizeof(int),
00255                             "red-black subtree sizes");
00256     node -> rbn_package = (struct bu_rb_package **)
00257                 bu_malloc(nm_orders * sizeof(struct bu_rb_package *),
00258                             "red-black packages");
00259     rblp = (struct bu_rb_list *)
00260                 bu_malloc(sizeof(struct bu_rb_list),
00261                             "red-black list element");
00262     rblp -> rbl_magic = BU_RB_LIST_MAGIC;
00263     rblp -> rbl_node = node;
00264     BU_LIST_PUSH(&(tree -> rbt_nodes.l), rblp);
00265     node -> rbn_list_pos = rblp;
00266 
00267     /*
00268      *  Fill in the package
00269      */
00270     package -> rbp_magic = BU_RB_PKG_MAGIC;
00271     package -> rbp_data = data;
00272     for (order = 0; order < nm_orders; ++order)
00273         (package -> rbp_node)[order] = node;
00274 
00275     /*
00276      *  Fill in the node
00277      */
00278     node -> rbn_magic = BU_RB_NODE_MAGIC;
00279     node -> rbn_tree = tree;
00280     for (order = 0; order < nm_orders; ++order)
00281         (node -> rbn_package)[order] = package;
00282     node -> rbn_pkg_refs = nm_orders;
00283 
00284     /*
00285      *  If the tree was empty, install this node as the root
00286      *  and give it a null parent and null children
00287      */
00288     if (bu_rb_root(tree, 0) == bu_rb_null(tree))
00289         for (order = 0; order < nm_orders; ++order)
00290         {
00291             bu_rb_root(tree, order) = node;
00292             bu_rb_parent(node, order) =
00293             bu_rb_left_child(node, order) =
00294             bu_rb_right_child(node, order) = bu_rb_null(tree);
00295             bu_rb_set_color(node, order, BU_RB_BLACK);
00296             bu_rb_size(node, order) = 1;
00297             if (tree -> rbt_debug & BU_RB_DEBUG_OS)
00298                 bu_log("bu_rb_insert(<%x>, <%x>, <%x>): size(%x, %d)=%d\n",
00299                     tree, data, node, node, order, bu_rb_size(node, order));
00300         }
00301     /*  Otherwise, insert the node into the tree */
00302     else
00303     {
00304         for (order = 0; order < nm_orders; ++order)
00305             result += _rb_insert(tree, order, node);
00306         if (tree -> rbt_debug & BU_RB_DEBUG_UNIQ)
00307             bu_log("bu_rb_insert(<%x>, <%x>, <%x>) will return %d\n",
00308                 tree, data, node, result);
00309     }
00310 
00311     ++(tree -> rbt_nm_nodes);
00312     bu_rb_current(tree) = node;
00313     return (result);
00314 }
00315 
00316 /**                     _ R B _ S E T _ U N I Q ( )
00317  *
00318  *          Raise or lower the uniqueness flag for one linear order
00319  *                          of a red-black tree
00320  *
00321  *      This function has three parameters: the tree, the order for which
00322  *      to modify the flag, and the new value for the flag.  _rb_set_uniq()
00323  *      sets the specified flag to the specified value and returns the
00324  *      previous value of the flag.
00325  */
00326 static int _rb_set_uniq (bu_rb_tree *tree, int order, int new_value)
00327 {
00328     int prev_value;
00329 
00330     BU_CKMAG(tree, BU_RB_TREE_MAGIC, "red-black tree");
00331     BU_RB_CKORDER(tree, order);
00332     new_value = (new_value != 0);
00333 
00334     prev_value = bu_rb_get_uniqueness(tree, order);
00335     bu_rb_set_uniqueness(tree, order, new_value);
00336     return (prev_value);
00337 }
00338 
00339 /*                       B U _ R B _ U N I Q _ O N ( )
00340  *                      B U _ R B _ U N I Q _ O F F ( )
00341  *
00342  *              Applications interface to _rb_set_uniq()
00343  *
00344  *      These functions have two parameters: the tree and the order for
00345  *      which to require uniqueness/permit nonuniqueness.  Each sets the
00346  *      specified flag to the specified value and returns the previous
00347  *      value of the flag.
00348  */
00349 int bu_rb_uniq_on (bu_rb_tree *tree, int order)
00350 {
00351     return (_rb_set_uniq(tree, order, 1));
00352 }
00353 
00354 int bu_rb_uniq_off (bu_rb_tree *tree, int order)
00355 {
00356     return (_rb_set_uniq(tree, order, 0));
00357 }
00358 
00359 /**                      B U _ R B _ I S _ U N I Q ( )
00360  *
00361  *        Query the uniqueness flag for one order of a red-black tree
00362  *
00363  *      This function has two parameters: the tree and the order for
00364  *      which to query uniqueness.
00365  */
00366 int bu_rb_is_uniq (bu_rb_tree *tree, int order)
00367 {
00368     BU_CKMAG(tree, BU_RB_TREE_MAGIC, "red-black tree");
00369     BU_RB_CKORDER(tree, order);
00370 
00371     return(bu_rb_get_uniqueness(tree, order));
00372 }
00373 
00374 /**                     B U _ R B _ S E T _ U N I Q V ( )
00375  *
00376  *          Set the uniqueness flags for all the linear orders
00377  *                          of a red-black tree
00378  *
00379  *      This function has two parameters: the tree and a bitv_t
00380  *      encoding the flag values.  bu_rb_set_uniqv() sets the flags
00381  *      according to the bits in flag_rep.  For example, if
00382  *      flag_rep = 1011_2, then the first, second, and fourth
00383  *      orders are specified unique, and the third is specified
00384  *      not-necessarily unique.
00385  */
00386 void bu_rb_set_uniqv (bu_rb_tree *tree, bitv_t flag_rep)
00387 {
00388     int nm_orders;
00389     int order;
00390 
00391     BU_CKMAG(tree, BU_RB_TREE_MAGIC, "red-black tree");
00392 
00393     nm_orders = tree -> rbt_nm_orders;
00394     for (order = 0; order < nm_orders; ++order)
00395         bu_rb_set_uniqueness(tree, order, 0);
00396 
00397     for (order = 0; (flag_rep != 0) && (order < nm_orders); flag_rep >>= 1,
00398                                                             ++order)
00399         if (flag_rep & 0x1)
00400             bu_rb_set_uniqueness(tree, order, 1);
00401 
00402     if (flag_rep != 0)
00403         bu_log("bu_rb_set_uniqv(): Ignoring bits beyond rightmost %d\n",
00404             nm_orders);
00405 }
00406 
00407 /**                 _ R B _ S E T _ U N I Q _ A L L ( )
00408  *
00409  *          Raise or lower the uniqueness flags for all the linear orders
00410  *                          of a red-black tree
00411  *
00412  *      This function has two parameters: the tree, and the new value
00413  *      for all the flags.
00414  */
00415 static void _rb_set_uniq_all (bu_rb_tree *tree, int new_value)
00416 {
00417     int nm_orders;
00418     int order;
00419 
00420     BU_CKMAG(tree, BU_RB_TREE_MAGIC, "red-black tree");
00421     new_value = (new_value != 0);
00422 
00423     nm_orders = tree -> rbt_nm_orders;
00424     for (order = 0; order < nm_orders; ++order)
00425         bu_rb_set_uniqueness(tree, order, new_value);
00426 }
00427 
00428 /**                  B U _ R B _ U N I Q _ A L L _ O N ( )
00429  *                  B U _ R B _ U N I Q _ A L L _ O F F ( )
00430  *
00431  *            Applications interface to _rb_set_uniq_all()
00432  *
00433  *      These functions have one parameter: the tree for which to
00434  *      require uniqueness/permit nonuniqueness.
00435  */
00436 void bu_rb_uniq_all_on (bu_rb_tree *tree)
00437 {
00438     _rb_set_uniq_all(tree, 1);
00439 }
00440 
00441 void bu_rb_uniq_all_off (bu_rb_tree *tree)
00442 {
00443     _rb_set_uniq_all(tree, 0);
00444 }
00445 /*@}*/
00446 
00447 /*
00448  * Local Variables:
00449  * mode: C
00450  * tab-width: 8
00451  * c-basic-offset: 4
00452  * indent-tabs-mode: t
00453  * End:
00454  * ex: shiftwidth=4 tabstop=8
00455  */

Generated on Mon Sep 18 01:24:48 2006 for BRL-CAD by  doxygen 1.4.6