The LevAWC Project
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Pages
avltree.c
Go to the documentation of this file.
1 /*
2  * _____
3  * ANSI / ___/
4  * / /__
5  * \___/
6  *
7  * Filename: avltree.c
8  * Author : Kyle Loudon/Dan Levin
9  * Date : Fri Mar 22 12:40:45 GMT 2013
10  * Version : 0.51
11  * ---
12  * Description: An AVL Tree - with some extensions.
13  *
14  * Date Revision message
15  * 150331 This code ready for version 0.51
16  */
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include "utils.h"
25 #include "avltree.h"
26 
35 #define AVLTREE_PRINT_LEVEL_PADDING 4
36 
37 struct AvlTreeNode_
38 {
39  void *data;
40  int hidden;
41  int factor;
42  struct AvlTreeNode_ *left;
43  struct AvlTreeNode_ *right;
44 };
45 
46 struct AvlTree_
47 {
48  int size;
49  int (*compare)(const void *key1, const void *key2);
50  void (*destroy)(void *data);
51  struct AvlTreeNode_ *root;
52 };
53 
54 /* STATIC FUNCTION DECLARATIONS */
55 static void rotate_left(AvlTreeNode *node);
56 static void rotate_right(AvlTreeNode *node);
57 static void destroy_left(AvlTree tree, AvlTreeNode node);
58 static void destroy_right(AvlTree tree, AvlTreeNode node);
59 static int insert(AvlTree tree, AvlTreeNode *node, const void *data, int *balanced);
60 static int hide(AvlTree tree, AvlTreeNode node, const void *data);
61 static int lookup(AvlTree tree, AvlTreeNode node, void **data);
62 static void print_tree(AvlTreeNode node, int level, void (*callback)(const void *data));
63 static void preorder(AvlTreeNode node, void (*callback)(const void *data));
64 static void inorder(AvlTreeNode node, void (*callback)(const void *data));
65 static void postorder(AvlTreeNode node, void (*callback)(const void *data));
66 static int treeheight(AvlTreeNode node, int depth);
67 static int avltree_insleft(AvlTree tree, AvlTreeNode node, const void *data);
68 static int avltree_insright(AvlTree tree, AvlTreeNode node, const void *data);
69 
70 /* FUNCTION DEFINITIONS -------------------------------------------------------- */
71 AvlTree AVLTREEinit(int (*compare)(const void *key1, const void *key2), void (*destroy)(void *data))
72 {
73  AvlTree tree;
74 
75  if ((tree = (AvlTree)malloc(sizeof(struct AvlTree_)))==NULL)
76  return NULL;
77 
78  tree->size = 0;
79  tree->compare = compare;
80  tree->destroy = destroy;
81  tree->root = NULL;
82 
83  return tree;
84 }
85 
87 {
88  destroy_left(tree, NULL);
89  free(tree);
90 }
91 
92 int AVLTREEinsert(AvlTree tree, const void *data)
93 {
94  int balanced = 0;
95 
96  return insert(tree, &tree->root, data, &balanced);
97 }
98 
99 int AVLTREEremove(AvlTree tree, const void *data)
100 {
101  return hide(tree, tree->root, data);
102 }
103 
104 int AVLTREElookup(AvlTree tree, void **data)
105 {
106  return lookup(tree, tree->root, data);
107 }
108 
110 {
111  return tree->size;
112 }
113 
115 {
116  return tree->root;
117 }
118 
120 {
121  return node == NULL;
122 }
123 
125 {
126  return node->left == NULL && node->right == NULL;
127 }
128 
130 {
131  return node->data;
132 }
133 
135 {
136  return node->left;
137 }
138 
140 {
141  return node->right;
142 }
143 
145 {
146  return treeheight(AVLTREEroot(tree), 0);
147 }
148 
149 void AVLTREEprint(AvlTree tree, void (*callback)(const void *data))
150 {
151  /* Now - print the entire tree... */
152  printf("\nAVL TREE STATUS: Size(%d nodes)/Height(%d levels)/(XX=hidden) ---\n", AVLTREEsize(tree), AVLTREEheight(tree));
153  print_tree(AVLTREEroot(tree), 0, callback);
154 }
155 
156 void AVLTREEpreorder(AvlTree tree, void (*callback)(const void *data))
157 {
158  preorder(tree->root, callback);
159 }
160 
161 void AVLTREEinorder(AvlTree tree, void (*callback)(const void *data))
162 {
163  inorder(tree->root, callback);
164 }
165 
166 void AVLTREEpostorder(AvlTree tree, void (*callback)(const void *data))
167 {
168  postorder(tree->root, callback);
169 }
170 
171 /* STATIC FUNCTION DEFINITIONS ------------------------------------------ */
172 
173 /* --- Function: static void rotate_left(AvlTreeNode *node) --- */
174 static void rotate_left(AvlTreeNode *node)
175 {
176  AvlTreeNode left, grandchild;
177 
178  left = (*node)->left;
179 
180  if (left->factor == AVL_LFT_HEAVY)
181  {
182  /* Perform an LL rotation... */
183  (*node)->left = left->right;
184  left->right = *node;
185  (*node)->factor = AVL_BALANCED;
186  left->factor = AVL_BALANCED;
187  *node = left;
188  }
189  else
190  {
191  /* Perform an LR rotation... */
192  grandchild = left->right;
193  left->right = grandchild->left;
194  grandchild->left = left;
195  (*node)->left = grandchild->right;
196  grandchild->right = *node;
197 
198  switch (grandchild->factor)
199  {
200  case AVL_LFT_HEAVY:
201  (*node)->factor = AVL_RGT_HEAVY;
202  left->factor = AVL_BALANCED;
203  break;
204 
205  case AVL_BALANCED:
206  (*node)->factor = AVL_BALANCED;
207  left->factor = AVL_BALANCED;
208  break;
209  case AVL_RGT_HEAVY:
210  (*node)->factor = AVL_BALANCED;
211  left->factor = AVL_LFT_HEAVY;
212  break;
213  }
214 
215  grandchild->factor = AVL_BALANCED;
216  *node = grandchild;
217  }
218 }
219 
220 /* --- Function: static void rotate_right(AvlTreeNode *node) --- */
221 static void rotate_right(AvlTreeNode *node)
222 {
223  AvlTreeNode right, grandchild;
224 
225  right = (*node)->right;
226 
227  if (right->factor == AVL_RGT_HEAVY)
228  {
229  /* Perform an RR rotation... */
230  (*node)->right = right->left;
231  right->left = *node;
232  (*node)->factor = AVL_BALANCED;
233  right->factor = AVL_BALANCED;
234  *node = right;
235  }
236  else
237  {
238  /* Perform an RL rotation... */
239  grandchild = right->left;
240  right->left = grandchild->right;
241  grandchild->right = right;
242  (*node)->right = grandchild->left;
243  grandchild->left = *node;
244 
245  switch (grandchild->factor)
246  {
247  case AVL_LFT_HEAVY:
248  (*node)->factor = AVL_BALANCED;
249  right->factor = AVL_RGT_HEAVY;
250  break;
251  case AVL_BALANCED:
252  (*node)->factor = AVL_BALANCED;
253  right->factor = AVL_BALANCED;
254  break;
255  case AVL_RGT_HEAVY:
256  (*node)->factor = AVL_LFT_HEAVY;
257  right->factor = AVL_BALANCED;
258  break;
259  }
260 
261  grandchild->factor = AVL_BALANCED;
262  *node = grandchild;
263  }
264 }
265 
266 /* --- Function: static void destroy_left(AvlTree tree, AvlTreeNode node) --- */
267 static void destroy_left(AvlTree tree, AvlTreeNode node)
268 {
269  AvlTreeNode *position;
270 
271  /* Destruction of an empty tree is not allowed.. */
272  if (tree->size == 0)
273  return;
274 
275  /* Determine where to destroy nodes... */
276  if (node == NULL)
277  position = &tree->root;
278  else
279  position = &node->left;
280 
281  /* Destroy the nodes... */
282  if (*position != NULL)
283  {
284  destroy_left(tree, *position);
285  destroy_right(tree, *position);
286 
287  if (tree->destroy != NULL)
288  {
289  /* Call a user-defined function to free dynamically allocated data */
290  tree->destroy((*position)->data);
291  }
292  /* Now, free the node itself... */
293  free(*position);
294  *position = NULL;
295 
296  /* Adjust the size of the tree to account for the destroyed node... */
297  tree->size--;
298  }
299 }
300 
301 /* --- Function: static void destroy_right(AvlTree tree, AvlTreeNode node) --- */
302 static void destroy_right(AvlTree tree, AvlTreeNode node)
303 {
304  AvlTreeNode *position;
305 
306  /* Destruction of an empty tree is not allowed.. */
307  if (tree->size == 0)
308  return;
309 
310  /* Determine where to destroy nodes... */
311  if (node == NULL)
312  position = &tree->root;
313  else
314  position = &node->right;
315 
316  /* Destroy the nodes... */
317  if (*position != NULL)
318  {
319  destroy_left(tree, *position);
320  destroy_right(tree, *position);
321 
322  if (tree->destroy != NULL)
323  {
324  /* Call a user-defined function to free dynamically allocated data */
325  tree->destroy((*position)->data);
326  }
327  /* Now, free the node itself... */
328  free(*position);
329  *position = NULL;
330 
331  /* Adjust the size of the tree to account for the destroyed node... */
332  tree->size--;
333  }
334 }
335 
336 /* --- Function: static int insert(AvlTree tree, AvlTreeNode *node, const void *data, int *balanced) --- */
337 static int insert(AvlTree tree, AvlTreeNode *node, const void *data, int *balanced)
338 {
339  // AvlTreeNode avl_data;
340  int cmpval, retval;
341 
342  /* Insert the data into the tree... */
343  if ((*node) == NULL)
344  {
345  return avltree_insleft(tree, *node, data);
346  }
347  else
348  {
349  /* Handle insertion into a tree that is not empty... */
350  cmpval = tree->compare(data, (*node)->data);
351 
352  if (cmpval < 0)
353  {
354  /* Move to the left... */
355  if ((*node)->left == NULL)
356  {
357  if (avltree_insleft(tree, *node, data) != 0)
358  return -1;
359 
360  *balanced = 0;
361  }
362  else
363  {
364  if ((retval = insert(tree, &(*node)->left, data, balanced)) != 0)
365  {
366  return retval;
367  }
368  }
369 
370  /* Ensure that the tree remains balanced... */
371  if (!(*balanced))
372  {
373  switch ((*node)->factor)
374  {
375  case AVL_LFT_HEAVY:
376  rotate_left(node);
377  *balanced = 1;
378  break;
379  case AVL_BALANCED:
380  (*node)->factor = AVL_LFT_HEAVY;
381  break;
382  case AVL_RGT_HEAVY:
383  (*node)->factor = AVL_BALANCED;
384  *balanced = 1;
385  }
386  }
387  } /* if (cmpval < 0) - end */
388  else if (cmpval > 0)
389  {
390  /* Move to the right... */
391  if ((*node)->right == NULL)
392  {
393  if (avltree_insright(tree, *node, data) != 0)
394  return -1;
395 
396  *balanced = 0;
397  }
398  else
399  {
400  if ((retval = insert(tree, &(*node)->right, data, balanced)) != 0)
401  {
402  return retval;
403  }
404  }
405 
406  /* Ensure that the tree remains balanced... */
407  if (!(*balanced))
408  {
409  switch ((*node)->factor)
410  {
411  case AVL_LFT_HEAVY:
412  (*node)->factor = AVL_BALANCED;
413  *balanced = 1;
414  break;
415  case AVL_BALANCED:
416  (*node)->factor = AVL_RGT_HEAVY;
417  break;
418  case AVL_RGT_HEAVY:
419  rotate_right(node);
420  *balanced = 1;
421  }
422  }
423  } /* if (cmpval > 0) - end */
424  else
425  {
426  /* Handle finding a copy of the data... */
427  if (!((*node)->hidden))
428  {
429  /* Do nothing since the data is in the tree - and not hidden... */
430  return 1;
431  }
432  else
433  {
434  /* Insert the new data - and mark it as not hidden... */
435  if (tree->destroy != NULL)
436  {
437  /* Destroy the hidden data since it is being replaced.. */
438  tree->destroy((*node)->data);
439  }
440 
441  (*node)->data = (void *)data;
442  (*node)->hidden = 0;
443 
444  /* Do not rebalance because the tree structure is unchanged.. */
445  *balanced = 1;
446  }
447  }
448  }
449 
450  return 0; /* Successful insertion completed! */
451 }
452 
453 /* --- Function: static int hide(AvlTree tree, AvlTreeNode node, const void *data) --- */
454 static int hide(AvlTree tree, AvlTreeNode node, const void *data)
455 {
456  int cmpval, retval;
457 
458  if (node == NULL)
459  {
460  /* Return that the data was not found... */
461  return -1;
462  }
463 
464  cmpval = tree->compare(data, node->data);
465 
466  if (cmpval < 0)
467  {
468  /* Move to the left... */
469  retval = hide(tree, node->left, data);
470  }
471  else if (cmpval > 0)
472  {
473  /* Move to the right... */
474  retval = hide(tree, node->right, data);
475  }
476  else /* Node found - hidden or not..! */
477  {
478  if (!(node->hidden))
479  {
480  /* Mark the node as hidden... */
481  node->hidden = 1;
482  /* Return success... */
483  retval = 0;
484  }
485  else
486  return -1;
487  }
488 
489  return retval;
490 }
491 
492 /* --- Function: static int lookup(AvlTree tree, AvlTreeNode node, void **data) --- */
493 static int lookup(AvlTree tree, AvlTreeNode node, void **data)
494 {
495  int cmpval, retval;
496 
497  if (node == NULL)
498  {
499  /* Return that the data was not found... */
500  return -1;
501  }
502 
503  cmpval = tree->compare(*data, node->data);
504 
505  if (cmpval < 0)
506  {
507  /* Move to the left... */
508  retval = lookup(tree, node->left, data);
509  }
510  else if (cmpval > 0)
511  {
512  /* Move to the right... */
513  retval = lookup(tree, node->right, data);
514  }
515  else
516  {
517  /* Node found - or hidden..! */
518  if (!(node->hidden) )
519  {
520  /* Pass back the data from the tree... */
521  *data = node->data;
522  retval = 0;
523  }
524  else
525  {
526  /* Return that the data was not found! */
527  return -1;
528  }
529  }
530 
531  return retval;
532 }
533 
534 static void print_tree(AvlTreeNode node, int level, void (*callback)(const void *data))
535 {
536  char *p_msk;
537 
538  /* Print current element data */
539  p_msk = (char *)malloc((AVLTREE_PRINT_LEVEL_PADDING*level+1)*sizeof(char));
540  assert(p_msk);
541  memset(p_msk, '-', AVLTREE_PRINT_LEVEL_PADDING*level);
542  p_msk[AVLTREE_PRINT_LEVEL_PADDING*level] = '\0';
543  printf("%s", p_msk);
544  free(p_msk);
545  /* Recursion condition */
546  if (AVLTREEis_eob(node))
547  {
548  printf("NIL");
549  printf("\n");
550  return;
551  }
552  else
553  {
554  if (node->hidden)
555  printf(" XX");
556  else
557  callback(AVLTREEdata(node));
558  printf("\n");
559  }
560 
561  /* Recursively traverse and print both "subtrees"... */
562  print_tree(AVLTREEleft(node), level+1, callback);
563  print_tree(AVLTREEright(node), level+1, callback);
564 }
565 
566 /* --- Function: void preorder(AvlTreeNode node, void (*callback)(const void *data)) --- */
567 static void preorder(AvlTreeNode node, void (*callback)(const void *data))
568 {
569  if (node)
570  {
571  /* Handle current node... */
572  callback(node->data);
573  /* Traverse left subtree - recursively in preorder... */
574  preorder(node->left, callback);
575  /* Traverse right subtree - recursively in preorder... */
576  preorder(node->right, callback);
577  }
578 }
579 
580 /* --- Function: void inorder(AvlTreeNode node, void (*callback)(const void *data)) --- */
581 static void inorder(AvlTreeNode node, void (*callback)(const void *data))
582 {
583  if (node)
584  {
585  /* Traverse left subtree - recursively in inorder... */
586  inorder(node->left, callback);
587  /* Handle current node... */
588  callback(node->data);
589  /* Traverse right subtree - recursively in inorder... */
590  inorder(node->right, callback);
591  }
592 }
593 
594 /* --- Function: void postorder(AvlTreeNode node, void (*callback)(const void *data)) --- */
595 static void postorder(AvlTreeNode node, void (*callback)(const void *data))
596 {
597  if (node)
598  {
599  /* Traverse left subtree - recursively in postorder... */
600  postorder(node->left, callback);
601  /* Traverse right subtree - recursively in postorder... */
602  postorder(node->right, callback);
603  /* Handle current node... */
604  callback(node->data);
605  }
606 }
607 
608 /* --- Function: int treeheight(AvlTreeNode node, int depth) --- */
609 static int treeheight(AvlTreeNode node, int depth)
610 {
611  if (!node)
612  return depth;
613  else
614  return maxval(treeheight(node->left, depth+1),
615  treeheight(node->right, depth+1));
616 }
617 
618 static int avltree_insleft(AvlTree tree, AvlTreeNode node, const void *data)
619 {
620  AvlTreeNode new_node, *position;
621 
622  /* Determine where to insert the node... */
623  if (node == NULL)
624  {
625  /* Allow insertion at the root only in an empty tree */
626  if (tree->size > 0)
627  return -1;
628 
629  position = &tree->root;
630  }
631  else
632  {
633  /* Normally allow insertion only at the end of a branch */
634  if (node->left != NULL)
635  return -1;
636 
637  position = &node->left;
638  }
639 
640  /* Allocate storage for the node */
641  if ((new_node = (AvlTreeNode)malloc(sizeof(struct AvlTreeNode_))) == NULL)
642  return -1;
643 
644  /* Insert the node into the tree */
645  new_node->data = (void *)data;
646  new_node->factor = AVL_BALANCED;
647  new_node->hidden = 0;
648  new_node->left = NULL;
649  new_node->right = NULL;
650  *position = new_node;
651 
652  /* Adjust the size of the tree to account for the inserted node */
653  tree->size++;
654 
655  return 0;
656 }
657 
658 static int avltree_insright(AvlTree tree, AvlTreeNode node, const void *data)
659 {
660  AvlTreeNode new_node, *position;
661 
662  /* Determine where to insert the node... */
663  if (node == NULL)
664  {
665  /* Allow insertion at the root only in an empty tree */
666  if (tree->size > 0)
667  return -1;
668 
669  position = &tree->root;
670  }
671  else
672  {
673  /* Normally allow insertion only at the end of a branch */
674  if (node->right != NULL)
675  return -1;
676 
677  position = &node->right;
678  }
679 
680  /* Allocate storage for the node */
681  if ((new_node = (AvlTreeNode)malloc(sizeof(struct AvlTreeNode_))) == NULL)
682  return -1;
683 
684  /* Insert the node into the tree */
685  new_node->data = (void *)data;
686  new_node->factor = AVL_BALANCED;
687  new_node->hidden = 0;
688  new_node->left = NULL;
689  new_node->right = NULL;
690  *position = new_node;
691 
692  /* Adjust the size of the tree to account for the inserted node */
693  tree->size++;
694 
695  return 0;
696 }