LIBAVL(3LIB)                 Interface Libraries                LIBAVL(3LIB)
NAME
     libavl - generic self-balancing binary search tree library
SYNOPSIS
     AVL Tree Library (libavl, -lavl)     
#include <sys/avl.h>DESCRIPTION
     The 
libavl library provides a generic implementation of AVL trees, a
     form of self-balancing binary tree.  The interfaces provided allow for
     an efficient way of implementing an ordered set of data structures and,
     due to its embeddable nature, allow for a single instance of a data
     structure to belong to multiple AVL trees.
     Each AVL tree contains entries of a single type of data structure.
     Rather than allocating memory for pointers for those data structures,
     the storage for the tree is embedded into the data structures by
     declaring a member of type 
avl_node_t.  When an AVL tree is created,
     through the use of 
avl_create(), it encodes the size of the data
     structure, the offset of the data structure, and a comparator function
     which is used to compare two instances of a data structure.  A data
     structure may be a member of multiple AVL trees by creating AVL trees
     which use different offsets (different members) into the data
     structure.
     AVL trees support both look up of an arbitrary item and ordered
     iteration over the contents of the entire tree.  In addition, from any
     node, you can find the previous and next entries in the tree, if they
     exist.  In addition, AVL trees support arbitrary insertion and
     deletion.
   Performance
     AVL trees are often used in place of linked lists.  Compared to the
     standard, intrusive, doubly linked list, it has the following
     performance characteristics:     
Lookup One Node             Lookup of a single node in a linked list is 
O(n), whereas
             lookup of a single node in an AVL tree is 
O(log(n)).     
Insert One Node             Inserting a single node into a linked list is 
O(1).  Inserting
             a single node into an AVL tree is 
O(log(n)).
             Note, insertions into an AVL tree always result in an ordered
             tree.  Insertions into a linked list do not guarantee order.
             If order is required, then the time to do the insertion into a
             linked list will depend on the time of the search algorithm
             being employed to find the place to insert at.     
Delete One Node             Deleting a single node from a linked list is 
O(1), whereas
             deleting a single node from an AVL tree takes 
O(log(n)) time.     
Delete All Nodes             Deleting all nodes from a linked list is 
O(n).  With an AVL
             tree, if using the 
avl_destroy_nodes(3AVL) function then
             deleting all nodes is 
O(n).  However, if iterating over each
             entry in the tree and then removing it using a while loop,             
avl_first(3AVL) and 
avl_remove(3AVL) then the time to remove
             all nodes is 
O(n * log(n)).     Visit the Next or Previous Node             Visiting the next or previous node in a linked list is 
O(1),
             whereas going from the next to the previous node in an AVL tree
             will take between 
O(1) and 
O(log(n)).
     In general, AVL trees are a good alternative for linked lists when
     order or lookup speed is important and a reasonable number of items
     will be present.
INTERFACES
     The shared object 
libavl.so.1 provides the public interfaces defined
     below.  See 
Intro(3) for additional information on shared object
     interfaces.  Individual functions are documented in their own manual
     pages.           
avl_add             avl_create           avl_destroy         avl_destroy_nodes           avl_find            avl_first           avl_insert          avl_insert_here           avl_is_empty        avl_last           avl_nearest         avl_numnodes           avl_remove          avl_swap           avl_update          avl_update_gt           avl_update_lt     In addition, the library defines C pre-processor macros which are
     defined below and documented in their own manual pages.           
AVL_NEXT            AVL_PREVTYPES
     The 
libavl library defines the following types:     
avl_tree_t     Type used for the root of the AVL tree.  Consumers define one of these
     for each of the different trees that they want to have.     
avl_node_t     Type used as the data node for an AVL tree.  One of these is embedded
     in each data structure that is the member of an AVL tree.     
avl_index_t     Type used to locate a position in a tree.  This is used with     
avl_find(3AVL) and 
avl_insert(3AVL).
LOCKING
     The 
libavl library provides no locking.  Callers that are using the
     same AVL tree from multiple threads need to provide their own
     synchronization.  If only one thread is ever accessing or modifying the
     AVL tree, then there are no synchronization concerns.  If multiple AVL
     trees exist, then they may all be used simultaneously; however, they
     are subject to the same rules around simultaneous access from a single
     thread.
     All routines are both 
Fork-safe and 
Async-Signal-Safe.  Callers may
     call functions in 
libavl from a signal handler and 
libavl calls are all
     safe in face of 
fork(2); however, if callers have their own locks, then
     they must make sure that they are accounted for by the use of routines
     such as 
pthread_atfork(3C).
EXAMPLES
     The following code shows examples of exercising all of the
     functionality that is present in 
libavl.  It can be compiled by using a
     C compiler and linking against 
libavl.  For example, given a file named
     avl.c, with gcc, one would run:
     $ gcc -Wall -o avl avl.c -lavl
     /*
      * Example of using AVL Trees
      */
     #include <sys/avl.h>
     #include <assert.h>
     #include <stddef.h>
     #include <stdlib.h>
     #include <stdio.h>
     static avl_tree_t inttree;
     /*
      * The structure that we're storing in an AVL tree.
      */
     typedef struct intnode {
             int in_val;
             avl_node_t in_avl;
     } intnode_t;
     static int
     intnode_comparator(const void *l, const void *r)
     {
             const intnode_t *li = l;
             const intnode_t *ri = r;
             if (li->in_val > ri->in_val)
                     return (1);
             if (li->in_val < ri->in_val)
                     return (-1);
             return (0);
     }
     /*
      * Create an AVL Tree
      */
     static void
     create_avl(void)
     {
             avl_create(&inttree, intnode_comparator, sizeof (intnode_t),
                 offsetof(intnode_t, in_avl));
     }
     /*
      * Add entries to the tree with the avl_add function.
      */
     static void
     fill_avl(void)
     {
             int i;
             intnode_t *inp;
             for (i = 0; i < 20; i++) {
                     inp = malloc(sizeof (intnode_t));
                     assert(inp != NULL);
                     inp->in_val = i;
                     avl_add(&inttree, inp);
             }
     }
     /*
      * Find entries in the AVL tree. Note, we create an intnode_t on the
      * stack that we use to look this up.
      */
     static void
     find_avl(void)
     {
             int i;
             intnode_t lookup, *inp;
             for (i = 10; i < 30; i++) {
                     lookup.in_val = i;
                     inp = avl_find(&inttree, &lookup, NULL);
                     if (inp == NULL) {
                             printf("Entry %d is not in the tree\n", i);
                     } else {
                             printf("Entry %d is in the tree\n",
                                 inp->in_val);
                     }
             }
     }
     /*
      * Walk the tree forwards
      */
     static void
     walk_forwards(void)
     {
             intnode_t *inp;
             for (inp = avl_first(&inttree); inp != NULL;
                 inp = AVL_NEXT(&inttree, inp)) {
                     printf("Found entry %d\n", inp->in_val);
             }
     }
     /*
      * Walk the tree backwards.
      */
     static void
     walk_backwards(void)
     {
             intnode_t *inp;
             for (inp = avl_last(&inttree); inp != NULL;
                 inp = AVL_PREV(&inttree, inp)) {
                     printf("Found entry %d\n", inp->in_val);
             }
     }
     /*
      * Determine the number of nodes in the tree and if it is empty or
      * not.
      */
     static void
     inttree_inspect(void)
     {
             printf("The tree is %s, there are %ld nodes in it\n",
                 avl_is_empty(&inttree) == B_TRUE ? "empty" : "not empty",
                 avl_numnodes(&inttree));
     }
     /*
      * Use avl_remove to remove entries from the tree.
      */
     static void
     remove_nodes(void)
     {
             int i;
             intnode_t lookup, *inp;
             for (i = 0; i < 20; i+= 4) {
                     lookup.in_val = i;
                     inp = avl_find(&inttree, &lookup, NULL);
                     if (inp != NULL)
                             avl_remove(&inttree, inp);
             }
     }
     /*
      * Find the nearest nodes in the tree.
      */
     static void
     nearest_nodes(void)
     {
             intnode_t lookup, *inp;
             avl_index_t where;
             lookup.in_val = 12;
             if (avl_find(&inttree, &lookup, &where) != NULL)
                     abort();
             inp = avl_nearest(&inttree, where, AVL_BEFORE);
             assert(inp != NULL);
             printf("closest node before 12 is: %d\n", inp->in_val);
             inp = avl_nearest(&inttree, where, AVL_AFTER);
             assert(inp != NULL);
             printf("closest node after 12 is: %d\n", inp->in_val);
     }
     static void
     insert_avl(void)
     {
             intnode_t lookup, *inp;
             avl_index_t where;
             lookup.in_val = 12;
             if (avl_find(&inttree, &lookup, &where) != NULL)
                     abort();
             inp = malloc(sizeof (intnode_t));
             assert(inp != NULL);
             avl_insert(&inttree, inp, where);
     }
     static void
     swap_avl(void)
     {
             avl_tree_t swap;
             avl_create(&swap, intnode_comparator, sizeof (intnode_t),
                 offsetof(intnode_t, in_avl));
             avl_swap(&inttree, &swap);
             inttree_inspect();
             avl_swap(&inttree, &swap);
             inttree_inspect();
     }
     static void
     update_avl(void)
     {
             intnode_t lookup, *inp;
             avl_index_t where;
             lookup.in_val = 9;
             inp = avl_find(&inttree, &lookup, &where);
             assert(inp != NULL);
             inp->in_val = 25;
             avl_update(&inttree, inp);
     }
     /*
      * Remove all remaining nodes in the tree. We first use
      * avl_destroy_nodes to empty the tree, then avl_destroy to finish.
      */
     static void
     cleanup(void)
     {
             intnode_t *inp;
             void *c = NULL;
             while ((inp = avl_destroy_nodes(&inttree, &c)) != NULL) {
                     free(inp);
             }
             avl_destroy(&inttree);
     }
     int
     main(void)
     {
             create_avl();
             inttree_inspect();
             fill_avl();
             find_avl();
             walk_forwards();
             walk_backwards();
             inttree_inspect();
             remove_nodes();
             inttree_inspect();
             nearest_nodes();
             insert_avl();
             inttree_inspect();
             swap_avl();
             update_avl();
             cleanup();
             return (0);
     }
INTERFACE STABILITY
     CommittedMT-Level     See 
Locking.SEE ALSO
     Intro(3), 
pthread_atfork(3C)     avl_add(3AVL), 
avl_create(3AVL), 
avl_destroy(3AVL),     
avl_destroy_nodes(3AVL), 
avl_find(3AVL), 
avl_first(3AVL),     
avl_insert(3AVL), 
avl_insert_here(3AVL), 
avl_is_empty(3AVL),     
avl_last(3AVL), 
avl_nearest(3AVL), 
avl_numnodes(3AVL),     
avl_remove(3AVL), 
avl_swap(3AVL), 
avl_update(3AVL),     
avl_update_gt(3AVL), 
avl_update_lt(3AVL)     Adel'son-Vel'skiy, G. M. and Landis, Ye. M., 
An Algorithm for the     Organization of Information, No. 2, Vol. 16, 263-266, Deklady Akademii
     Nauk, USSR, Moscow, 1962.
illumos                       January 27, 2024                       illumos