2 AVL balanced tree library
4 > Created (Julienne Walker): June 17, 2003
5 > Modified (Julienne Walker): September 24, 2005
7 #include "jsw_avltree.h"
12 #define HEIGHT_LIMIT 64 /* Tallest allowable tree */
15 typedef struct jsw_avlnode {
16 int balance; /* Balance factor */
17 void *data; /* User-defined content */
18 struct jsw_avlnode *link[2]; /* Left (0) and right (1) links */
22 jsw_avlnode_t *root; /* Top of the tree */
23 cmp_f cmp; /* Compare two items */
24 dup_f dup; /* Clone an item (user-defined) */
25 rel_f rel; /* Destroy an item (user-defined) */
26 size_t size; /* Number of items (user-defined) */
30 jsw_avltree_t *tree; /* Paired tree */
31 jsw_avlnode_t *it; /* Current node */
32 jsw_avlnode_t *path[HEIGHT_LIMIT]; /* Traversal path */
33 size_t top; /* Top of stack */
36 /* Two way single rotation */
37 #define jsw_single(root,dir) do { \
38 jsw_avlnode_t *save = root->link[!dir]; \
39 root->link[!dir] = save->link[dir]; \
40 save->link[dir] = root; \
44 /* Two way double rotation */
45 #define jsw_double(root,dir) do { \
46 jsw_avlnode_t *save = root->link[!dir]->link[dir]; \
47 root->link[!dir]->link[dir] = save->link[!dir]; \
48 save->link[!dir] = root->link[!dir]; \
49 root->link[!dir] = save; \
50 save = root->link[!dir]; \
51 root->link[!dir] = save->link[dir]; \
52 save->link[dir] = root; \
56 /* Adjust balance before double rotation */
57 #define jsw_adjust_balance(root,dir,bal) do { \
58 jsw_avlnode_t *n = root->link[dir]; \
59 jsw_avlnode_t *nn = n->link[!dir]; \
60 if ( nn->balance == 0 ) \
61 root->balance = n->balance = 0; \
62 else if ( nn->balance == bal ) { \
63 root->balance = -bal; \
66 else { /* nn->balance == -bal */ \
73 /* Rebalance after insertion */
74 #define jsw_insert_balance(root,dir) do { \
75 jsw_avlnode_t *n = root->link[dir]; \
76 int bal = dir == 0 ? -1 : +1; \
77 if ( n->balance == bal ) { \
78 root->balance = n->balance = 0; \
79 jsw_single ( root, !dir ); \
81 else { /* n->balance == -bal */ \
82 jsw_adjust_balance ( root, dir, bal ); \
83 jsw_double ( root, !dir ); \
87 /* Rebalance after deletion */
88 #define jsw_remove_balance(root,dir,done) do { \
89 jsw_avlnode_t *n = root->link[!dir]; \
90 int bal = dir == 0 ? -1 : +1; \
91 if ( n->balance == -bal ) { \
92 root->balance = n->balance = 0; \
93 jsw_single ( root, dir ); \
95 else if ( n->balance == bal ) { \
96 jsw_adjust_balance ( root, !dir, -bal ); \
97 jsw_double ( root, dir ); \
99 else { /* n->balance == 0 */ \
100 root->balance = -bal; \
102 jsw_single ( root, dir ); \
107 static jsw_avlnode_t *new_node ( jsw_avltree_t *tree, void *data )
109 jsw_avlnode_t *rn = malloc ( sizeof *rn );
115 rn->data = tree->dup ( data );
116 rn->link[0] = rn->link[1] = NULL;
121 jsw_avltree_t *jsw_avlnew ( cmp_f cmp, dup_f dup, rel_f rel )
123 jsw_avltree_t *rt = malloc ( sizeof *rt );
137 void jsw_avldelete ( jsw_avltree_t *tree )
139 jsw_avlnode_t *it = tree->root;
142 /* Destruction by rotation */
143 while ( it != NULL ) {
144 if ( it->link[0] == NULL ) {
147 tree->rel ( it->data );
153 it->link[0] = save->link[1];
163 void *jsw_avlfind ( jsw_avltree_t *tree, void *data )
165 jsw_avlnode_t *it = tree->root;
167 while ( it != NULL ) {
168 int cmp = tree->cmp ( it->data, data );
173 it = it->link[cmp < 0];
176 return it == NULL ? NULL : it->data;
179 int jsw_avlinsert ( jsw_avltree_t *tree, void *data )
181 /* Empty tree case */
182 if ( tree->root == NULL ) {
183 tree->root = new_node ( tree, data );
184 if ( tree->root == NULL )
188 jsw_avlnode_t head = {0}; /* Temporary tree root */
189 jsw_avlnode_t *s, *t; /* Place to rebalance and parent */
190 jsw_avlnode_t *p, *q; /* Iterator and save pointer */
193 /* Set up false root to ease maintenance */
195 t->link[1] = tree->root;
197 /* Search down the tree, saving rebalance points */
198 for ( s = p = t->link[1]; ; p = q ) {
199 dir = tree->cmp ( p->data, data ) < 0;
205 if ( q->balance != 0 ) {
211 p->link[dir] = q = new_node ( tree, data );
215 /* Update balance factors */
216 for ( p = s; p != q; p = p->link[dir] ) {
217 dir = tree->cmp ( p->data, data ) < 0;
218 p->balance += dir == 0 ? -1 : +1;
221 q = s; /* Save rebalance point for parent fix */
223 /* Rebalance if necessary */
224 if ( abs ( s->balance ) > 1 ) {
225 dir = tree->cmp ( s->data, data ) < 0;
226 jsw_insert_balance ( s, dir );
230 if ( q == head.link[1] )
233 t->link[q == t->link[1]] = s;
241 int jsw_avlerase ( jsw_avltree_t *tree, void *data )
243 if ( tree->root != NULL ) {
244 jsw_avlnode_t *it, *up[HEIGHT_LIMIT];
245 int upd[HEIGHT_LIMIT], top = 0;
250 /* Search down tree and save path */
254 else if ( tree->cmp ( it->data, data ) == 0 )
257 /* Push direction and node onto stack */
258 upd[top] = tree->cmp ( it->data, data ) < 0;
261 it = it->link[upd[top - 1]];
264 /* Remove the node */
265 if ( it->link[0] == NULL || it->link[1] == NULL ) {
266 /* Which child is not null? */
267 int dir = it->link[0] == NULL;
271 up[top - 1]->link[upd[top - 1]] = it->link[dir];
273 tree->root = it->link[dir];
275 tree->rel ( it->data );
279 /* Find the inorder successor */
280 jsw_avlnode_t *heir = it->link[1];
283 /* Save this path too */
287 while ( heir->link[0] != NULL ) {
290 heir = heir->link[0];
295 it->data = heir->data;
298 /* Unlink successor and fix parent */
299 up[top - 1]->link[up[top - 1] == it] = heir->link[1];
301 tree->rel ( heir->data );
305 /* Walk back up the search path */
306 while ( --top >= 0 && !done ) {
307 /* Update balance factors */
308 up[top]->balance += upd[top] != 0 ? -1 : +1;
310 /* Terminate or rebalance as necessary */
311 if ( abs ( up[top]->balance ) == 1 )
313 else if ( abs ( up[top]->balance ) > 1 ) {
314 jsw_remove_balance ( up[top], upd[top], done );
318 up[top - 1]->link[upd[top - 1]] = up[top];
330 size_t jsw_avlsize ( jsw_avltree_t *tree )
335 jsw_avltrav_t *jsw_avltnew ( void )
337 return malloc ( sizeof ( jsw_avltrav_t ) );
340 void jsw_avltdelete ( jsw_avltrav_t *trav )
346 First step in traversal,
349 static void *start ( jsw_avltrav_t *trav, jsw_avltree_t *tree, int dir )
352 trav->it = tree->root;
355 /* Build a path to work with */
356 if ( trav->it != NULL ) {
357 while ( trav->it->link[dir] != NULL ) {
358 trav->path[trav->top++] = trav->it;
359 trav->it = trav->it->link[dir];
363 return trav->it == NULL ? NULL : trav->it->data;
367 Subsequent traversal steps,
368 handles ascending and descending
370 static void *move ( jsw_avltrav_t *trav, int dir )
372 if ( trav->it->link[dir] != NULL ) {
373 /* Continue down this branch */
374 trav->path[trav->top++] = trav->it;
375 trav->it = trav->it->link[dir];
377 while ( trav->it->link[!dir] != NULL ) {
378 trav->path[trav->top++] = trav->it;
379 trav->it = trav->it->link[!dir];
383 /* Move to the next branch */
387 if ( trav->top == 0 ) {
393 trav->it = trav->path[--trav->top];
394 } while ( last == trav->it->link[dir] );
397 return trav->it == NULL ? NULL : trav->it->data;
400 void *jsw_avltfirst ( jsw_avltrav_t *trav, jsw_avltree_t *tree )
402 return start ( trav, tree, 0 ); /* Min value */
405 void *jsw_avltlast ( jsw_avltrav_t *trav, jsw_avltree_t *tree )
407 return start ( trav, tree, 1 ); /* Max value */
410 void *jsw_avltnext ( jsw_avltrav_t *trav )
412 return move ( trav, 1 ); /* Toward larger items */
415 void *jsw_avltprev ( jsw_avltrav_t *trav )
417 return move ( trav, 0 ); /* Toward smaller items */