TREE(3) BSD Library Functions Manual TREE(3) NAME TREE_ENTRY, TREE_HEAD, TREE_INITIALIZER, TREE_INIT, TREE_DEFINE, TREE_INSERT, TREE_FIND, TREE_REMOVE, TREE_FORWARD_APPLY, TREE_REVERSE_APPLY - implementation of AVL balanced binary trees SYNOPSIS #include <tree.h> TREE_ENTRY(NODE); TREE_HEAD(TREE, NODE); TREE_INITIALIZER(int (*relation)(NODE *, NODE *)); TREE_INIT(TREE *head, int (*relation)(NODE *, NODE *)); TREE_DEFINE(NODE, NAME); TREE_INSERT(TREE *head, NODE, NODE *elm); TREE_REMOVE(TREE *head, NODE, NODE *elm); TREE_FIND(TREE *head, NODE, NODE *elm); TREE_FORWARD_APPLY(TREE *head, void (*functio_n)(TYPE *elm, void *data), void *data); TREE_REVERSE_APPLY(TREE *head, void (*functio_n)(TYPE *elm, void *data), void *data); DESCRIPTION These macros define and operate on AVL balanced binary trees. The trees support the following functionality: 1. Insertion of a new entry in the tree. 2. Removal of any entry in the tree. 3. Search for any entry in the tree. 4. Forward traversal through the tree. 5. Backward traversal through the tree. In the macro definitions, NODE is the name (tag) of a user-defined struc- ture, that must contain a field of type TREE_ENTRY named NAME, and TREE is the name (tag) of a user-defined structure representing the head of the tree that must be declared using the macro TREE_HEAD. A tree is headed by a structure defined by the TREE_HEAD macro. This structure contains a pointer to the root node of the tree and a pointer to a function that defines the ordering relation between nodes. A TREE_HEAD structure is declared as follows: TREE_HEAD(TREE, NODE) head; where TREE is the name (tag) of the structure to be defined, and NODE is the name (struture tag) of the elements to be inserted into the tree. A pointer to the head of the tree can later be declared as: struct TREE *treep; (The name treep is user selectable.) The prototypes for the four macros that accept function arguments might be confusing. If namespace pollution were not an issue the following declarations using explicit typedefs would be exactly equivalent: typedef int (*ORDER_FN)(NODE *lhs, NODE *rhs); TREE_INIT(TREE *head, ORDER_FN relation); TREE_INITIALIZER(ORDER_FN relation); typedef int (*VISITOR)(NODE *elm, void *client_data); TREE_FORWARD_APPLY(TREE *head, VISITOR func, void *client_data); TREE_REVERSE_APPLY(TREE *head, VISITOR func, void *client_data); The macro TREE_ENTRY declares a structure that connects the elements in the tree. The macro TREE_INIT initializes the tree referenced by head ordered according to the given relation, which must be a function taking two arguments of type NODE and returning -1, zero or 1 if the first argument is considered less than, equal to or greater than the second argument respectively. TREE_INITIALIZER provides a corresponding static initial- izer. The macro TREE_INSERT inserts the new element elm into the tree and rebalances it. The macro TREE_REMOVE removes the element elm from the tree and rebal- ances it. The macro TREE_FIND finds an element in the tree that is equal (according to the tree's ordering relation) to elm, and returns a pointer to it or NULL if no such element was found. The macro TREE_FORWARD_APPLY walks the tree in-order from left to right and calls function for each node visited passing the node as the first argument and data as the second argument. The macro TREE_REVERSE_APPLY is similar but walks the tree from right to left. The macro TREE_DEFINE defines several recursive helper functions needed to implement trees containing elements of type NODE linked through a field with the given NAME. This macro should be invoked exactly once for each type of tree node (a unique combination of NODE tag and entry NAME) in a given program. EXAMPLES The following program reads lines from standard input into a tree struc- ture, inserting each unique line into the tree. On EOF it prints the lines in forward and reverse alphabetical order. #include "tree.h" #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct _Node { char *word; TREE_ENTRY(_Node) linkage; } Node; typedef TREE_HEAD(_Tree, _Node) Tree; TREE_DEFINE(_Node, linkage); int fence = 0; Node *Node_new(char *word) { Node *self = (Node *)calloc(1, sizeof(Node)); self->word = strdup(word); return self; } int Node_compare(Node *lhs, Node *rhs) { return strcmp(lhs->word, rhs->word); } void Node_printer(Node *self, void *stream) { if (fence) { fprintf((FILE *)stream, "%s", self->word); --fence; } } int main(int argc, char **argv) { int count = 0; Tree tree = TREE_INITIALIZER(Node_compare); char line[80]; while (fgets(line, sizeof(line), stdin)) { Node test = { line }; Node *ptr = TREE_FIND(&tree, _Node, linkage, &test); if (ptr) printf("ignoring duplicate line: %s", line); else { TREE_INSERT(&tree, _Node, linkage, Node_new(line)); ++count; } } fence = 20; printf("first %d elements, forwards:\n", fence); TREE_FORWARD_APPLY(&tree, _Node, linkage, Node_printer, stdout); printf("\n"); fence = 20; printf("last %d elements, backwards:\n", fence); TREE_REVERSE_APPLY(&tree, _Node, linkage, Node_printer, stdout); printf("\n"); printf("inserted %d elements into a tree of depth %d\n", count, TREE_DEPTH(&tree, linkage)); return 0; } The above program typically sorts the contents of /usr/dict/words in less than twice the time of the system sort(1) utility. RETURN VALUES The macro TREE_FIND returns a pointer to an element in the tree equal to elm or NULL if no such element exists. COMPATIBILITY The interface conforms as closely as possible to the that of the standard BSD queue(3) macros. SEE ALSO queue(3) Georgii M. Adelson-Velskii and Evgenii M. Landis, "An algorithm for the organization of information", Doklady Akademii Nauk SSSR, 146:263-266, 1962, Russian. Myron J. Ricci (trans.), Soviet Math., 3:1259-1263, 1962, English. Donald E. Knuth, The Art of Computer Programming, Vol. 3: Sorting and Searching, 459, 1998, 2nd ed. AUTHORS The software and manual pages were written by Ian Piumarta. Copyright (c) 2005 Ian Piumarta All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Soft- ware'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. BUGS o The implementation should be generalised to support linear lists in which elements can be searched, inserted and deleted according either to an ordering relation or to an explicit numeric index, all in O(log N) time. Please send bug reports to the author at: firstName (at) lastName (dot) com. (See AUTHORS above for suitable values of firstName and lastName.) BSD November 11, 2005 BSD