REDBLACK(3)

NAME

redblack - red-black tree operations

SYNOPSIS

#include "common.h"

#include <stdio.h>

#include "bu.h"

struct bu_rb_tree *bu_rb_create (description,
                                 nm_orders,
                                 order_funcs);

DESCRIPTION

These routines implement red-black trees, a form of balanced binary trees, in such a way that all the basic dynamic set operations (e.g., insertion, deletion, search, minimum, maximum, predecessor, and successor) and order-statistic operations (i.e., select and rank) require no more than O(log n) time, where n is the number of nodes. They allow storage of arbitrary data structures at tree nodes and also support multiple simultaneous orders (trees) on the same nodes. The trees are based on comparison functions like those used by qsort(3). The routines are available only in libbu(3B).

bu_rb_create

allocates storage for and initializes the tree header. Description is an explanatory comment that the red-black tree package prints in its diagnostics, nm_orders is the number of simultaneous orders, and order_funcs points to the table of comparison functions (one for each order). These are called with two arguments that point to the application data blocks being compared. Each function must return an integer less than, equal to, or greater than zero according as the first argument is to be considered less than, equal to, or greater than the second. bu_rb_create returns a pointer to a bu_rb_tree structure. This pointer must be saved, as it is a required argument to all the other routines. bu_rb_create1 is similar, except that it creates a tree that supports only the single order specified by order_func.

The application can specify that the red-black tree package may not insert new nodes that compare equal in any of the orders to an existing node. Such uniqueness enforcement is switch selectable and may be controlled independently for each order and modified dynamically. The default behavior is not to enforce any uniqueness.

bu_rb_free

relinquishes the storage used by tree, calling free_data to dispose of the application data in the nodes. If free_data equals BU_RB_RETAIN_DATA (defined in "bu.h"), then the application data blocks are left unaffected. Otherwise, bu_rb_free calls free_data once for each block of application data, passing a pointer to the data. Since bu_rb_create1 allocates its own table of comparison functions, a memory leak will result if a tree returned by bu_rb_create1 is freed before this table is freed. For this reason, bu.h provides the macro bu_rb_free1(tree, free_data), which should be used instead of bu_rb_free when relinquishing a tree created by bu_rb_create1.

bu_rb_insert

creates a new node containing data and adds it to tree, provided that doing so would not violate current uniqueness requirements. If a uniqueness requirement would be violated, bu_rb_insert does nothing but return a negative integer, the absolute value of which is the first order for which a violation exists. Otherwise, the node is inserted in the appropriate place in each order, as determined by the comparison functions, and bu_rb_insert returns the number of orders for which the new node compared equal to an existing node in the tree.

bu_rb_uniq_on

specifies that subsequent insertion of nodes into tree should enforce uniqueness on order, and returns the previous setting of the switch. bu_rb_uniq_off specifies that subsequent insertion of nodes into tree should proceed without regard for uniqueness on order, and returns the previous setting of the switch. The macros bu_rb_uniq_on1(tree) and bu_rb_uniq_off1(tree) available in "bu.h", are similar, except that they control the first (perhaps only) order. bu_rb_is_uniq returns 1 if uniqueness is currently enforced for order in tree, and 0 otherwise. The macro bu_rb_is_uniq1(tree) available in "bu.h", is similar, except that it queries the first (perhaps only) order. bu_rb_uniq_all_on and bu_rb_uniq_all_off set all nm_orders orders identically on or off, and bu_rb_set_uniqv sets the orders according to the bit vector vec.

bu_rb_extreme

searches through tree to find a minimum or maximum node in one of the orders as determined by the corresponding comparison function. Sense is either SENSE_MIN or SENSE_MAX, and order specifies which order to search. bu_rb_extreme returns a pointer to the extreme data. The macros bu_rb_min(tree, order) and bu_rb_max(tree, order), available in "bu.h", are implemented in terms of bu_rb_extreme in the obvious way.

bu_rb_search

traverses tree searching for a node of which the contents equals data according to the comparison function specified by order. On success, bu_rb_search returns a pointer to the data in the matching node. Otherwise, it returns NULL. The macro bu_rb_search1(tree, data), available in "bu.h", is similar, except that it searches the first (perhaps only) order.

bu_rb_select

traverses tree to retrieve the kth order statistic (i.e., the data block of rank k, the kth-smallest data block) according to the comparison function specified by order, where k is between 1 and the number of nodes in tree, inclusive. On success, bu_rb_select returns a pointer to the block of data of rank k. Otherwise, it returns NULL. The macro bu_rb_select1(tree, k), available in "bu.h", is similar, except that it uses the first (perhaps only) order.

bu_rb_walk

traverses tree according to the comparison function specified by order. The function visit is called for each node in turn, being passed two arguments: a pointer to the data at that node and the depth of the node in the tree for the specified order. The type of tree traversal to perform, specified by trav_type, may be any one of PREORDER, INORDER, and POSTORDER. The macro bu_rb_walk1(tree, visit, trav_type), available in "bu.h", is similar, except that it walks the first (perhaps only) order.

bu_rb_diagnose_tree

traverses tree according to the comparison function specified by order, printing information about the various structures. The application may optionally store in the rbt_print member of the bu_rb_tree structure the address of an application-specific print routine. If this pointer is nonzero, bu_rb_diagnose_tree dereferences it to print information for the data at each node. The type of tree traversal to perform, specified by trav_type, may be any one of PREORDER, INORDER, and POSTORDER.

The bu_rb_tree structure contains a pointer to the node most recently accessed (e.g., inserted, discovered in a search, or selected by rank). When the most recent access failed, this current node is undefined. The following commands make use of the current node:

bu_rb_curr

returns a pointer to the data in the current node in order, or NULL if the current node is undefined. The macro bu_rb_curr1(tree), available in "bu.h", is similar, except that it returns a pointer to the data in the current node in the first (perhaps only) order.

bu_rb_delete

removes a block of application data from tree. Because the algorithms sometimes cause a single block of data to be stored in different nodes for the different orders, the application specifies order, which indicates the block of data (in the current node) to be removed. If the current node is defined, bu_rb_delete removes this block of data from every order. Otherwise, it prints a warning and returns. The macro bu_rb_delete1(tree), available in "bu.h", is similar, except that it removes the block of data in the first (perhaps only) order.

bu_rb_neighbor

returns a pointer to the data in the node adjacent (in order) to the current node, or NULL if the current node is undefined. sense, which may be one of SENSE_MIN and SENSE_MAX, specifies either predecessor or successor, respectively. The macros bu_rb_pred(tree, order) and bu_rb_succ(tree, order), available in "bu.h", are implemented in terms of bu_rb_neighbor in the obvious way.

bu_rb_rank

returns the rank (i.e., position expressed as an integer between 1 and the number of nodes in tree, inclusive) of the current node in order, or NULL if the current node is undefined. The macro bu_rb_rank1(tree), available in "bu.h", is similar, except that it uses the first (perhaps only) order.

The members of the bu_rb_tree structure, as defined in "bu.h", are classified into three classes based on their suitability for direct manipulation by applications.

  • Class I, members that applications may read directly, includes

    uint32_t rbt_magic; /* Magic no. for integrity check */
    int  rbt_nm_nodes;  /* Number of nodes */
  • Class II, members that applications may read or write directly as necessary, includes

    void (*rbt_print)();   /* Data pretty-print function */
    int  rbt_debug;        /* Debug bits */
    char *rbt_description; /* Comment for diagnostics */
  • Class III comprises members that applications should not manipulate directly; any access should be through the routines provided by the red-black tree package. They include

    int               rbt_nm_orders;   /* Number of orders */
    int               (**rbt_order)(); /* Comparison funcs */
    struct bu_rb_node **rbt_root;      /* The actual trees */
    char              *rbt_unique;     /* Uniqueness flags */
    struct bu_rb_node *rbt_current;    /* Current node */
    struct bu_rb_list rbt_nodes;       /* All nodes */
    struct bu_rb_list rbt_packages;    /* All packages */
    struct bu_rb_node *rbt_empty_node; /* Sentinel for nil */

The distinction between classes I and III is not critical, but any direct modification of members in either class will result in unpredictable (probably dire) results. The order of the members within the bu_rb_tree structure is subject to change in future releases.

Diagnostic output may be requested by setting the debug bits in the bu_rb_tree structure using the debug bit flags defined in "bu.h".

SEE ALSO

-libbu(3B)-, -qsort(3)-.

AUTHOR

Paul Tanenbaum

This software is Copyright (c) 1989-2021 by the United States Government as represented by U.S. Army Research Laboratory.

BUG REPORTS

Reports of bugs or problems should be submitted via electronic mail to devs@brlcad.org