08349b18ea
In collaboration with: dougm Reviewed by: alc Sponsored by: The FreeBSD Foundation (kib) MFC after: 3 days Differential revision: https://reviews.freebsd.org/D36001
782 lines
20 KiB
Groff
782 lines
20 KiB
Groff
.\" $OpenBSD: tree.3,v 1.7 2002/06/12 01:09:20 provos Exp $
|
|
.\"
|
|
.\" Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
|
.\" All rights reserved.
|
|
.\"
|
|
.\" Redistribution and use in source and binary forms, with or without
|
|
.\" modification, are permitted provided that the following conditions
|
|
.\" are met:
|
|
.\" 1. Redistributions of source code must retain the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer.
|
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer in the
|
|
.\" documentation and/or other materials provided with the distribution.
|
|
.\" 3. All advertising materials mentioning features or use of this software
|
|
.\" must display the following acknowledgement:
|
|
.\" This product includes software developed by Niels Provos.
|
|
.\" 4. The name of the author may not be used to endorse or promote products
|
|
.\" derived from this software without specific prior written permission.
|
|
.\"
|
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
.\"
|
|
.\" $FreeBSD$
|
|
.\"
|
|
.Dd July 27, 2020
|
|
.Dt TREE 3
|
|
.Os
|
|
.Sh NAME
|
|
.Nm SPLAY_PROTOTYPE ,
|
|
.Nm SPLAY_GENERATE ,
|
|
.Nm SPLAY_ENTRY ,
|
|
.Nm SPLAY_HEAD ,
|
|
.Nm SPLAY_INITIALIZER ,
|
|
.Nm SPLAY_ROOT ,
|
|
.Nm SPLAY_EMPTY ,
|
|
.Nm SPLAY_NEXT ,
|
|
.Nm SPLAY_MIN ,
|
|
.Nm SPLAY_MAX ,
|
|
.Nm SPLAY_FIND ,
|
|
.Nm SPLAY_LEFT ,
|
|
.Nm SPLAY_RIGHT ,
|
|
.Nm SPLAY_FOREACH ,
|
|
.Nm SPLAY_INIT ,
|
|
.Nm SPLAY_INSERT ,
|
|
.Nm SPLAY_REMOVE ,
|
|
.Nm RB_PROTOTYPE ,
|
|
.Nm RB_PROTOTYPE_STATIC ,
|
|
.Nm RB_PROTOTYPE_INSERT ,
|
|
.Nm RB_PROTOTYPE_INSERT_COLOR ,
|
|
.Nm RB_PROTOTYPE_REMOVE ,
|
|
.Nm RB_PROTOTYPE_REMOVE_COLOR ,
|
|
.Nm RB_PROTOTYPE_FIND ,
|
|
.Nm RB_PROTOTYPE_NFIND ,
|
|
.Nm RB_PROTOTYPE_NEXT ,
|
|
.Nm RB_PROTOTYPE_PREV ,
|
|
.Nm RB_PROTOTYPE_MINMAX ,
|
|
.Nm RB_PROTOTYPE_REINSERT ,
|
|
.Nm RB_GENERATE ,
|
|
.Nm RB_GENERATE_STATIC ,
|
|
.Nm RB_GENERATE_INSERT ,
|
|
.Nm RB_GENERATE_INSERT_COLOR ,
|
|
.Nm RB_GENERATE_REMOVE ,
|
|
.Nm RB_GENERATE_REMOVE_COLOR ,
|
|
.Nm RB_GENERATE_FIND ,
|
|
.Nm RB_GENERATE_NFIND ,
|
|
.Nm RB_GENERATE_NEXT ,
|
|
.Nm RB_GENERATE_PREV ,
|
|
.Nm RB_GENERATE_MINMAX ,
|
|
.Nm RB_GENERATE_REINSERT ,
|
|
.Nm RB_ENTRY ,
|
|
.Nm RB_HEAD ,
|
|
.Nm RB_INITIALIZER ,
|
|
.Nm RB_ROOT ,
|
|
.Nm RB_EMPTY ,
|
|
.Nm RB_NEXT ,
|
|
.Nm RB_PREV ,
|
|
.Nm RB_MIN ,
|
|
.Nm RB_MAX ,
|
|
.Nm RB_FIND ,
|
|
.Nm RB_NFIND ,
|
|
.Nm RB_LEFT ,
|
|
.Nm RB_RIGHT ,
|
|
.Nm RB_PARENT ,
|
|
.Nm RB_FOREACH ,
|
|
.Nm RB_FOREACH_FROM ,
|
|
.Nm RB_FOREACH_SAFE ,
|
|
.Nm RB_FOREACH_REVERSE ,
|
|
.Nm RB_FOREACH_REVERSE_FROM ,
|
|
.Nm RB_FOREACH_REVERSE_SAFE ,
|
|
.Nm RB_INIT ,
|
|
.Nm RB_INSERT ,
|
|
.Nm RB_REMOVE ,
|
|
.Nm RB_REINSERT ,
|
|
.Nm RB_AUGMENT
|
|
.Nm RB_UPDATE_AUGMENT
|
|
.Nd "implementations of splay and rank-balanced (wavl) trees"
|
|
.Sh SYNOPSIS
|
|
.In sys/tree.h
|
|
.Fn SPLAY_PROTOTYPE NAME TYPE FIELD CMP
|
|
.Fn SPLAY_GENERATE NAME TYPE FIELD CMP
|
|
.Fn SPLAY_ENTRY TYPE
|
|
.Fn SPLAY_HEAD HEADNAME TYPE
|
|
.Ft "struct TYPE *"
|
|
.Fn SPLAY_INITIALIZER "SPLAY_HEAD *head"
|
|
.Fn SPLAY_ROOT "SPLAY_HEAD *head"
|
|
.Ft bool
|
|
.Fn SPLAY_EMPTY "SPLAY_HEAD *head"
|
|
.Ft "struct TYPE *"
|
|
.Fn SPLAY_NEXT NAME "SPLAY_HEAD *head" "struct TYPE *elm"
|
|
.Ft "struct TYPE *"
|
|
.Fn SPLAY_MIN NAME "SPLAY_HEAD *head"
|
|
.Ft "struct TYPE *"
|
|
.Fn SPLAY_MAX NAME "SPLAY_HEAD *head"
|
|
.Ft "struct TYPE *"
|
|
.Fn SPLAY_FIND NAME "SPLAY_HEAD *head" "struct TYPE *elm"
|
|
.Ft "struct TYPE *"
|
|
.Fn SPLAY_LEFT "struct TYPE *elm" "SPLAY_ENTRY NAME"
|
|
.Ft "struct TYPE *"
|
|
.Fn SPLAY_RIGHT "struct TYPE *elm" "SPLAY_ENTRY NAME"
|
|
.Fn SPLAY_FOREACH VARNAME NAME "SPLAY_HEAD *head"
|
|
.Ft void
|
|
.Fn SPLAY_INIT "SPLAY_HEAD *head"
|
|
.Ft "struct TYPE *"
|
|
.Fn SPLAY_INSERT NAME "SPLAY_HEAD *head" "struct TYPE *elm"
|
|
.Ft "struct TYPE *"
|
|
.Fn SPLAY_REMOVE NAME "SPLAY_HEAD *head" "struct TYPE *elm"
|
|
.Fn RB_PROTOTYPE NAME TYPE FIELD CMP
|
|
.Fn RB_PROTOTYPE_STATIC NAME TYPE FIELD CMP
|
|
.Fn RB_PROTOTYPE_INSERT NAME TYPE ATTR
|
|
.Fn RB_PROTOTYPE_INSERT_COLOR NAME TYPE ATTR
|
|
.Fn RB_PROTOTYPE_REMOVE NAME TYPE ATTR
|
|
.Fn RB_PROTOTYPE_REMOVE_COLOR NAME TYPE ATTR
|
|
.Fn RB_PROTOTYPE_FIND NAME TYPE ATTR
|
|
.Fn RB_PROTOTYPE_NFIND NAME TYPE ATTR
|
|
.Fn RB_PROTOTYPE_NEXT NAME TYPE ATTR
|
|
.Fn RB_PROTOTYPE_PREV NAME TYPE ATTR
|
|
.Fn RB_PROTOTYPE_MINMAX NAME TYPE ATTR
|
|
.Fn RB_PROTOTYPE_REINSERT NAME TYPE ATTR
|
|
.Fn RB_GENERATE NAME TYPE FIELD CMP
|
|
.Fn RB_GENERATE_STATIC NAME TYPE FIELD CMP
|
|
.Fn RB_GENERATE_INSERT NAME TYPE FIELD CMP ATTR
|
|
.Fn RB_GENERATE_INSERT_COLOR NAME TYPE FIELD ATTR
|
|
.Fn RB_GENERATE_REMOVE NAME TYPE FIELD ATTR
|
|
.Fn RB_GENERATE_REMOVE_COLOR NAME TYPE FIELD ATTR
|
|
.Fn RB_GENERATE_FIND NAME TYPE FIELD CMP ATTR
|
|
.Fn RB_GENERATE_NFIND NAME TYPE FIELD CMP ATTR
|
|
.Fn RB_GENERATE_NEXT NAME TYPE FIELD ATTR
|
|
.Fn RB_GENERATE_PREV NAME TYPE FIELD ATTR
|
|
.Fn RB_GENERATE_MINMAX NAME TYPE FIELD ATTR
|
|
.Fn RB_GENERATE_REINSERT NAME TYPE FIELD CMP ATTR
|
|
.Fn RB_ENTRY TYPE
|
|
.Fn RB_HEAD HEADNAME TYPE
|
|
.Fn RB_INITIALIZER "RB_HEAD *head"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_ROOT "RB_HEAD *head"
|
|
.Ft "bool"
|
|
.Fn RB_EMPTY "RB_HEAD *head"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_NEXT NAME "RB_HEAD *head" "struct TYPE *elm"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_PREV NAME "RB_HEAD *head" "struct TYPE *elm"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_MIN NAME "RB_HEAD *head"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_MAX NAME "RB_HEAD *head"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_FIND NAME "RB_HEAD *head" "struct TYPE *elm"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_NFIND NAME "RB_HEAD *head" "struct TYPE *elm"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_LEFT "struct TYPE *elm" "RB_ENTRY NAME"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_RIGHT "struct TYPE *elm" "RB_ENTRY NAME"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_PARENT "struct TYPE *elm" "RB_ENTRY NAME"
|
|
.Fn RB_FOREACH VARNAME NAME "RB_HEAD *head"
|
|
.Fn RB_FOREACH_FROM "VARNAME" "NAME" "POS_VARNAME"
|
|
.Fn RB_FOREACH_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME"
|
|
.Fn RB_FOREACH_REVERSE VARNAME NAME "RB_HEAD *head"
|
|
.Fn RB_FOREACH_REVERSE_FROM "VARNAME" "NAME" "POS_VARNAME"
|
|
.Fn RB_FOREACH_REVERSE_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME"
|
|
.Ft void
|
|
.Fn RB_INIT "RB_HEAD *head"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_INSERT NAME "RB_HEAD *head" "struct TYPE *elm"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_REMOVE NAME "RB_HEAD *head" "struct TYPE *elm"
|
|
.Ft "struct TYPE *"
|
|
.Fn RB_REINSERT NAME "RB_HEAD *head" "struct TYPE *elm"
|
|
.Ft "void"
|
|
.Fn RB_AUGMENT NAME "struct TYPE *elm"
|
|
.Ft "void"
|
|
.Fn RB_UPDATE_AUGMENT NAME "struct TYPE *elm"
|
|
.Sh DESCRIPTION
|
|
These macros define data structures for different types of trees:
|
|
splay trees and rank-balanced (wavl) trees.
|
|
.Pp
|
|
In the macro definitions,
|
|
.Fa TYPE
|
|
is the name tag of a user defined structure that must contain a field of type
|
|
.Vt SPLAY_ENTRY ,
|
|
or
|
|
.Vt RB_ENTRY ,
|
|
named
|
|
.Fa ENTRYNAME .
|
|
The argument
|
|
.Fa HEADNAME
|
|
is the name tag of a user defined structure that must be declared
|
|
using the macros
|
|
.Fn SPLAY_HEAD ,
|
|
or
|
|
.Fn RB_HEAD .
|
|
The argument
|
|
.Fa NAME
|
|
has to be a unique name prefix for every tree that is defined.
|
|
.Pp
|
|
The function prototypes are declared with
|
|
.Fn SPLAY_PROTOTYPE ,
|
|
.Fn RB_PROTOTYPE ,
|
|
or
|
|
.Fn RB_PROTOTYPE_STATIC .
|
|
The function bodies are generated with
|
|
.Fn SPLAY_GENERATE ,
|
|
.Fn RB_GENERATE ,
|
|
or
|
|
.Fn RB_GENERATE_STATIC .
|
|
See the examples below for further explanation of how these macros are used.
|
|
.Sh SPLAY TREES
|
|
A splay tree is a self-organizing data structure.
|
|
Every operation on the tree causes a splay to happen.
|
|
The splay moves the requested
|
|
node to the root of the tree and partly rebalances it.
|
|
.Pp
|
|
This has the benefit that request locality causes faster lookups as
|
|
the requested nodes move to the top of the tree.
|
|
On the other hand, every lookup causes memory writes.
|
|
.Pp
|
|
The Balance Theorem bounds the total access time for
|
|
.Ar m
|
|
operations and
|
|
.Ar n
|
|
inserts on an initially empty tree as
|
|
.Fn O "\*[lp]m + n\*[rp]lg n" .
|
|
The
|
|
amortized cost for a sequence of
|
|
.Ar m
|
|
accesses to a splay tree is
|
|
.Fn O "lg n" .
|
|
.Pp
|
|
A splay tree is headed by a structure defined by the
|
|
.Fn SPLAY_HEAD
|
|
macro.
|
|
A
|
|
structure is declared as follows:
|
|
.Bd -ragged -offset indent
|
|
.Fn SPLAY_HEAD HEADNAME TYPE
|
|
.Va head ;
|
|
.Ed
|
|
.Pp
|
|
where
|
|
.Fa HEADNAME
|
|
is the name of the structure to be defined, and struct
|
|
.Fa TYPE
|
|
is the type of the elements to be inserted into the tree.
|
|
.Pp
|
|
The
|
|
.Fn SPLAY_ENTRY
|
|
macro declares a structure that allows elements to be connected in the tree.
|
|
.Pp
|
|
In order to use the functions that manipulate the tree structure,
|
|
their prototypes need to be declared with the
|
|
.Fn SPLAY_PROTOTYPE
|
|
macro,
|
|
where
|
|
.Fa NAME
|
|
is a unique identifier for this particular tree.
|
|
The
|
|
.Fa TYPE
|
|
argument is the type of the structure that is being managed
|
|
by the tree.
|
|
The
|
|
.Fa FIELD
|
|
argument is the name of the element defined by
|
|
.Fn SPLAY_ENTRY .
|
|
.Pp
|
|
The function bodies are generated with the
|
|
.Fn SPLAY_GENERATE
|
|
macro.
|
|
It takes the same arguments as the
|
|
.Fn SPLAY_PROTOTYPE
|
|
macro, but should be used only once.
|
|
.Pp
|
|
Finally,
|
|
the
|
|
.Fa CMP
|
|
argument is the name of a function used to compare tree nodes
|
|
with each other.
|
|
The function takes two arguments of type
|
|
.Vt "struct TYPE *" .
|
|
If the first argument is smaller than the second, the function returns a
|
|
value smaller than zero.
|
|
If they are equal, the function returns zero.
|
|
Otherwise, it should return a value greater than zero.
|
|
The compare
|
|
function defines the order of the tree elements.
|
|
.Pp
|
|
The
|
|
.Fn SPLAY_INIT
|
|
macro initializes the tree referenced by
|
|
.Fa head .
|
|
.Pp
|
|
The splay tree can also be initialized statically by using the
|
|
.Fn SPLAY_INITIALIZER
|
|
macro like this:
|
|
.Bd -ragged -offset indent
|
|
.Fn SPLAY_HEAD HEADNAME TYPE
|
|
.Va head
|
|
=
|
|
.Fn SPLAY_INITIALIZER &head ;
|
|
.Ed
|
|
.Pp
|
|
The
|
|
.Fn SPLAY_INSERT
|
|
macro inserts the new element
|
|
.Fa elm
|
|
into the tree.
|
|
.Pp
|
|
The
|
|
.Fn SPLAY_REMOVE
|
|
macro removes the element
|
|
.Fa elm
|
|
from the tree pointed by
|
|
.Fa head .
|
|
.Pp
|
|
The
|
|
.Fn SPLAY_FIND
|
|
macro can be used to find a particular element in the tree.
|
|
.Bd -literal -offset indent
|
|
struct TYPE find, *res;
|
|
find.key = 30;
|
|
res = SPLAY_FIND(NAME, head, &find);
|
|
.Ed
|
|
.Pp
|
|
The
|
|
.Fn SPLAY_ROOT ,
|
|
.Fn SPLAY_MIN ,
|
|
.Fn SPLAY_MAX ,
|
|
and
|
|
.Fn SPLAY_NEXT
|
|
macros can be used to traverse the tree:
|
|
.Bd -literal -offset indent
|
|
for (np = SPLAY_MIN(NAME, &head); np != NULL; np = SPLAY_NEXT(NAME, &head, np))
|
|
.Ed
|
|
.Pp
|
|
Or, for simplicity, one can use the
|
|
.Fn SPLAY_FOREACH
|
|
macro:
|
|
.Bd -ragged -offset indent
|
|
.Fn SPLAY_FOREACH np NAME head
|
|
.Ed
|
|
.Pp
|
|
The
|
|
.Fn SPLAY_EMPTY
|
|
macro should be used to check whether a splay tree is empty.
|
|
.Sh RANK-BALANCED TREES
|
|
Rank-balanced (RB) trees are a framework for defining height-balanced
|
|
binary search trees, including AVL and red-black trees.
|
|
Each tree node has an associated rank.
|
|
Balance conditions are expressed by conditions on the differences in
|
|
rank between any node and its children.
|
|
Rank differences are stored in each tree node.
|
|
.Pp
|
|
The balance conditions implemented by the RB macros lead to weak AVL
|
|
(wavl) trees, which combine the best aspects of AVL and red-black
|
|
trees.
|
|
Wavl trees rebalance after an insertion in the same way AVL trees do,
|
|
with the same worst-case time as red-black trees offer, and with
|
|
better balance in the resulting tree.
|
|
Wavl trees rebalance after a removal in a way that requires less
|
|
restructuring, in the worst case, than either AVL or red-black trees
|
|
do.
|
|
Removals can lead to a tree almost as unbalanced as a red-black
|
|
tree; insertions lead to a tree becoming as balanced as an AVL tree.
|
|
.Pp
|
|
A rank-balanced tree is headed by a structure defined by the
|
|
.Fn RB_HEAD
|
|
macro.
|
|
A
|
|
structure is declared as follows:
|
|
.Bd -ragged -offset indent
|
|
.Fn RB_HEAD HEADNAME TYPE
|
|
.Va head ;
|
|
.Ed
|
|
.Pp
|
|
where
|
|
.Fa HEADNAME
|
|
is the name of the structure to be defined, and struct
|
|
.Fa TYPE
|
|
is the type of the elements to be inserted into the tree.
|
|
.Pp
|
|
The
|
|
.Fn RB_ENTRY
|
|
macro declares a structure that allows elements to be connected in the tree.
|
|
.Pp
|
|
In order to use the functions that manipulate the tree structure,
|
|
their prototypes need to be declared with the
|
|
.Fn RB_PROTOTYPE
|
|
or
|
|
.Fn RB_PROTOTYPE_STATIC
|
|
macro,
|
|
where
|
|
.Fa NAME
|
|
is a unique identifier for this particular tree.
|
|
The
|
|
.Fa TYPE
|
|
argument is the type of the structure that is being managed
|
|
by the tree.
|
|
The
|
|
.Fa FIELD
|
|
argument is the name of the element defined by
|
|
.Fn RB_ENTRY .
|
|
Individual prototypes can be declared with
|
|
.Fn RB_PROTOTYPE_INSERT ,
|
|
.Fn RB_PROTOTYPE_INSERT_COLOR ,
|
|
.Fn RB_PROTOTYPE_REMOVE ,
|
|
.Fn RB_PROTOTYPE_REMOVE_COLOR ,
|
|
.Fn RB_PROTOTYPE_FIND ,
|
|
.Fn RB_PROTOTYPE_NFIND ,
|
|
.Fn RB_PROTOTYPE_NEXT ,
|
|
.Fn RB_PROTOTYPE_PREV ,
|
|
.Fn RB_PROTOTYPE_MINMAX ,
|
|
and
|
|
.Fn RB_PROTOTYPE_REINSERT
|
|
in case not all functions are required.
|
|
The individual prototype macros expect
|
|
.Fa NAME ,
|
|
.Fa TYPE ,
|
|
and
|
|
.Fa ATTR
|
|
arguments.
|
|
The
|
|
.Fa ATTR
|
|
argument must be empty for global functions or
|
|
.Fa static
|
|
for static functions.
|
|
.Pp
|
|
The function bodies are generated with the
|
|
.Fn RB_GENERATE
|
|
or
|
|
.Fn RB_GENERATE_STATIC
|
|
macro.
|
|
These macros take the same arguments as the
|
|
.Fn RB_PROTOTYPE
|
|
and
|
|
.Fn RB_PROTOTYPE_STATIC
|
|
macros, but should be used only once.
|
|
As an alternative individual function bodies are generated with the
|
|
.Fn RB_GENERATE_INSERT ,
|
|
.Fn RB_GENERATE_INSERT_COLOR ,
|
|
.Fn RB_GENERATE_REMOVE ,
|
|
.Fn RB_GENERATE_REMOVE_COLOR ,
|
|
.Fn RB_GENERATE_FIND ,
|
|
.Fn RB_GENERATE_NFIND ,
|
|
.Fn RB_GENERATE_NEXT ,
|
|
.Fn RB_GENERATE_PREV ,
|
|
.Fn RB_GENERATE_MINMAX ,
|
|
and
|
|
.Fn RB_GENERATE_REINSERT
|
|
macros.
|
|
.Pp
|
|
Finally,
|
|
the
|
|
.Fa CMP
|
|
argument is the name of a function used to compare tree nodes
|
|
with each other.
|
|
The function takes two arguments of type
|
|
.Vt "struct TYPE *" .
|
|
If the first argument is smaller than the second, the function returns a
|
|
value smaller than zero.
|
|
If they are equal, the function returns zero.
|
|
Otherwise, it should return a value greater than zero.
|
|
The compare
|
|
function defines the order of the tree elements.
|
|
.Pp
|
|
The
|
|
.Fn RB_INIT
|
|
macro initializes the tree referenced by
|
|
.Fa head .
|
|
.Pp
|
|
The rank-balanced tree can also be initialized statically by using the
|
|
.Fn RB_INITIALIZER
|
|
macro like this:
|
|
.Bd -ragged -offset indent
|
|
.Fn RB_HEAD HEADNAME TYPE
|
|
.Va head
|
|
=
|
|
.Fn RB_INITIALIZER &head ;
|
|
.Ed
|
|
.Pp
|
|
The
|
|
.Fn RB_INSERT
|
|
macro inserts the new element
|
|
.Fa elm
|
|
into the tree.
|
|
.Pp
|
|
The
|
|
.Fn RB_REMOVE
|
|
macro removes the element
|
|
.Fa elm
|
|
from the tree pointed by
|
|
.Fa head .
|
|
.Pp
|
|
The
|
|
.Fn RB_FIND
|
|
and
|
|
.Fn RB_NFIND
|
|
macros can be used to find a particular element in the tree.
|
|
.Pp
|
|
The
|
|
.Fn RB_FIND
|
|
macro returns the element in the tree equal to the provided
|
|
key, or
|
|
.Dv NULL
|
|
if there is no such element.
|
|
.Pp
|
|
The
|
|
.Fn RB_NFIND
|
|
macro returns the least element greater than or equal to the provided
|
|
key, or
|
|
.Dv NULL
|
|
if there is no such element.
|
|
.Bd -literal -offset indent
|
|
struct TYPE find, *res, *resn;
|
|
find.key = 30;
|
|
res = RB_FIND(NAME, head, &find);
|
|
resn = RB_NFIND(NAME, head, &find);
|
|
.Ed
|
|
.Pp
|
|
The
|
|
.Fn RB_ROOT ,
|
|
.Fn RB_MIN ,
|
|
.Fn RB_MAX ,
|
|
.Fn RB_NEXT ,
|
|
and
|
|
.Fn RB_PREV
|
|
macros can be used to traverse the tree:
|
|
.Pp
|
|
.Dl "for (np = RB_MIN(NAME, &head); np != NULL; np = RB_NEXT(NAME, &head, np))"
|
|
.Pp
|
|
Or, for simplicity, one can use the
|
|
.Fn RB_FOREACH
|
|
or
|
|
.Fn RB_FOREACH_REVERSE
|
|
macro:
|
|
.Bd -ragged -offset indent
|
|
.Fn RB_FOREACH np NAME head
|
|
.Ed
|
|
.Pp
|
|
The macros
|
|
.Fn RB_FOREACH_SAFE
|
|
and
|
|
.Fn RB_FOREACH_REVERSE_SAFE
|
|
traverse the tree referenced by head
|
|
in a forward or reverse direction respectively,
|
|
assigning each element in turn to np.
|
|
However, unlike their unsafe counterparts,
|
|
they permit both the removal of np
|
|
as well as freeing it from within the loop safely
|
|
without interfering with the traversal.
|
|
.Pp
|
|
Both
|
|
.Fn RB_FOREACH_FROM
|
|
and
|
|
.Fn RB_FOREACH_REVERSE_FROM
|
|
may be used to continue an interrupted traversal
|
|
in a forward or reverse direction respectively.
|
|
The head pointer is not required.
|
|
The pointer to the node from where to resume the traversal
|
|
should be passed as their last argument,
|
|
and will be overwritten to provide safe traversal.
|
|
.Pp
|
|
The
|
|
.Fn RB_EMPTY
|
|
macro should be used to check whether a rank-balanced tree is empty.
|
|
.Pp
|
|
The
|
|
.Fn RB_REINSERT
|
|
macro updates the position of the element
|
|
.Fa elm
|
|
in the tree.
|
|
This must be called if a member of a
|
|
.Nm tree
|
|
is modified in a way that affects comparison, such as by modifying
|
|
a node's key.
|
|
This is a lower overhead alternative to removing the element
|
|
and reinserting it again.
|
|
.Pp
|
|
The
|
|
.Fn RB_AUGMENT
|
|
macro updates augmentation data of the element
|
|
.Fa elm
|
|
in the tree.
|
|
By default, it has no effect.
|
|
It is not meant to be invoked by the RB user.
|
|
If
|
|
.Fn RB_AUGMENT
|
|
is defined by the RB user, then when an element is inserted or removed
|
|
from the tree, it is invoked for every element in the tree that is the
|
|
root of an altered subtree, working from the bottom of the tree up to
|
|
the top.
|
|
It is typically used to maintain some associative accumulation of tree
|
|
elements, such as sums, minima, maxima, and the like.
|
|
.Pp
|
|
The
|
|
.Fn RB_UPDATE_AUGMENT
|
|
macro updates augmentation data of the element
|
|
.Fa elm
|
|
and its ancestors in the tree.
|
|
If
|
|
.Fn RB_AUGMENT
|
|
is defined by the RB user, then when an element in the
|
|
tree is changed, without changing the order of items in the tree,
|
|
invoking this function on that element restores consistency of the
|
|
augmentation state of the tree as if the element had been removed and
|
|
inserted again.
|
|
.Sh EXAMPLES
|
|
The following example demonstrates how to declare a rank-balanced tree
|
|
holding integers.
|
|
Values are inserted into it and the contents of the tree are printed
|
|
in order.
|
|
To maintain the sum of the values in the tree, each element maintains
|
|
the sum of its value and the sums from its left and right subtrees.
|
|
Lastly, the internal structure of the tree is printed.
|
|
.Bd -literal -offset 3n
|
|
#include <sys/tree.h>
|
|
#include <err.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
struct node {
|
|
RB_ENTRY(node) entry;
|
|
int i, sum;
|
|
};
|
|
|
|
int
|
|
intcmp(struct node *e1, struct node *e2)
|
|
{
|
|
return (e1->i < e2->i ? -1 : e1->i > e2->i);
|
|
}
|
|
|
|
int
|
|
sumaug(struct node *e)
|
|
{
|
|
e->sum = e->i;
|
|
if (RB_LEFT(e, entry) != NULL)
|
|
e->sum += RB_LEFT(e, entry)->sum;
|
|
if (RB_RIGHT(e, entry) != NULL)
|
|
e->sum += RB_RIGHT(e, entry)->sum;
|
|
}
|
|
#define RB_AUGMENT(entry) sumaug(entry)
|
|
|
|
RB_HEAD(inttree, node) head = RB_INITIALIZER(&head);
|
|
RB_GENERATE(inttree, node, entry, intcmp)
|
|
|
|
int testdata[] = {
|
|
20, 16, 17, 13, 3, 6, 1, 8, 2, 4, 10, 19, 5, 9, 12, 15, 18,
|
|
7, 11, 14
|
|
};
|
|
|
|
void
|
|
print_tree(struct node *n)
|
|
{
|
|
struct node *left, *right;
|
|
|
|
if (n == NULL) {
|
|
printf("nil");
|
|
return;
|
|
}
|
|
left = RB_LEFT(n, entry);
|
|
right = RB_RIGHT(n, entry);
|
|
if (left == NULL && right == NULL)
|
|
printf("%d", n->i);
|
|
else {
|
|
printf("%d(", n->i);
|
|
print_tree(left);
|
|
printf(",");
|
|
print_tree(right);
|
|
printf(")");
|
|
}
|
|
}
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
int i;
|
|
struct node *n;
|
|
|
|
for (i = 0; i < sizeof(testdata) / sizeof(testdata[0]); i++) {
|
|
if ((n = malloc(sizeof(struct node))) == NULL)
|
|
err(1, NULL);
|
|
n->i = testdata[i];
|
|
RB_INSERT(inttree, &head, n);
|
|
}
|
|
|
|
RB_FOREACH(n, inttree, &head) {
|
|
printf("%d\en", n->i);
|
|
}
|
|
print_tree(RB_ROOT(&head));
|
|
printf("Sum of values = %d\n", RB_ROOT(&head)->sum);
|
|
printf("\en");
|
|
return (0);
|
|
}
|
|
.Ed
|
|
.Sh NOTES
|
|
Trying to free a tree in the following way is a common error:
|
|
.Bd -literal -offset indent
|
|
SPLAY_FOREACH(var, NAME, head) {
|
|
SPLAY_REMOVE(NAME, head, var);
|
|
free(var);
|
|
}
|
|
free(head);
|
|
.Ed
|
|
.Pp
|
|
Since
|
|
.Va var
|
|
is freed, the
|
|
.Fn FOREACH
|
|
macro refers to a pointer that may have been reallocated already.
|
|
Proper code needs a second variable.
|
|
.Bd -literal -offset indent
|
|
for (var = SPLAY_MIN(NAME, head); var != NULL; var = nxt) {
|
|
nxt = SPLAY_NEXT(NAME, head, var);
|
|
SPLAY_REMOVE(NAME, head, var);
|
|
free(var);
|
|
}
|
|
.Ed
|
|
.Pp
|
|
Both
|
|
.Fn RB_INSERT
|
|
and
|
|
.Fn SPLAY_INSERT
|
|
return
|
|
.Dv NULL
|
|
if the element was inserted in the tree successfully, otherwise they
|
|
return a pointer to the element with the colliding key.
|
|
.Pp
|
|
Accordingly,
|
|
.Fn RB_REMOVE
|
|
and
|
|
.Fn SPLAY_REMOVE
|
|
return the pointer to the removed element otherwise they return
|
|
.Dv NULL
|
|
to indicate an error.
|
|
.Sh SEE ALSO
|
|
.Xr arb 3 ,
|
|
.Xr queue 3
|
|
.Rs
|
|
.%A "Bernhard Haeupler"
|
|
.%A "Siddhartha Sen"
|
|
.%A "Robert E. Tarjan"
|
|
.%T "Rank-Balanced Trees"
|
|
.%U "http://sidsen.azurewebsites.net/papers/rb-trees-talg.pdf"
|
|
.%J "ACM Transactions on Algorithms"
|
|
.%V "11"
|
|
.%N "4"
|
|
.%D "June 2015"
|
|
.Re
|
|
.Sh HISTORY
|
|
The tree macros first appeared in
|
|
.Fx 4.6 .
|
|
.Sh AUTHORS
|
|
The author of the tree macros is
|
|
.An Niels Provos .
|