The LevAWC Project
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Pages
bitree.c
Go to the documentation of this file.
1 /*
2  * _____
3  * ANSI / ___/
4  * / /__
5  * \___/
6  *
7  * Filename: bitree.c
8  * Author : Kyle Loudon/Dan Levin
9  * Date : Fri Mar 22 12:40:45 GMT 2013
10  * Version : 0.51
11  * ---
12  * Description : A basic, miminal, binary tree ADT - written in ANSI C.
13  *
14  * 130217 Created this file
15  * 150331 This code ready for version 0.51
16  *
17  */
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #include "bitree.h"
26 
35 #define BITREE_PRINT_LEVEL_PADDING 4
36 
37 struct BiTreeNode_
38 {
39  void *data;
40  struct BiTreeNode_ *left;
41  struct BiTreeNode_ *right;
42 };
43 
44 struct BiTree_
45 {
46  int size;
47  int (*compare)(const void *key1, const void *key2);
48  void (*destroy)(void *data);
49  struct BiTreeNode_ *root;
50 };
51 
52 
53 /* STATIC FUNCTION DECLARATIONS */
54 static BiTreeNode remnode(BiTree tree, BiTreeNode node, void **data);
55 static int treeheight(BiTreeNode node, int depth);
56 static void print_tree(BiTreeNode node, int level, void (*callback)(const void *data));
57 static void preorder(BiTreeNode node, void (*callback)(const void *data));
58 static void inorder(BiTreeNode node, void (*callback)(const void *data));
59 static void postorder(BiTreeNode node, void (*callback)(const void *data));
60 
61 /* FUNCTION DEFINITIONS -------------------------------------------------------- */
62 BiTree BITREEinit(void (*destroy)(void *data))
63 {
64  BiTree tree;
65 
66  if ((tree = (BiTree)malloc(sizeof(struct BiTree_)))==NULL)
67  return NULL;
68 
69  tree->size = 0;
70  tree->destroy = destroy;
71  tree->root = NULL;
72 
73  return tree;
74 }
75 
77 {
78  /* Remove all nodes */
79  BITREEremleft(tree, NULL);
80 
81  /* Remove tree header */
82  free(tree);
83 }
84 
85 void BITREEsetcompare(BiTree tree, int (*compare)(const void *key1, const void *key2))
86 {
87  tree->compare = compare;
88 }
89 
90 int BITREEinsleft(BiTree tree, BiTreeNode node, const void *data)
91 {
92  BiTreeNode new_node, *position;
93 
94  /* Determine where to insert the node... */
95  if (node == NULL)
96  {
97  /* Allow insertion at the root only in an empty tree */
98  if (BITREEsize(tree) > 0)
99  return -1;
100 
101  position = &tree->root;
102  }
103  else
104  {
105  /* Normally allow insertion only at the end of a branch */
106  if (BITREEleft(node) != NULL)
107  return -1;
108 
109  position = &node->left;
110  }
111 
112  /* Allocate storage for the node */
113  if ((new_node = (BiTreeNode)malloc(sizeof(struct BiTreeNode_))) == NULL)
114  return -1;
115 
116  /* Insert the node into the tree */
117  new_node->data = (void *)data;
118  new_node->left = NULL;
119  new_node->right = NULL;
120  *position = new_node;
121 
122  /* Adjust the size of the tree to account for the inserted node */
123  tree->size++;
124 
125  return 0;
126 }
127 
128 int BITREEinsright(BiTree tree, BiTreeNode node, const void *data)
129 {
130  BiTreeNode new_node, *position;
131 
132  /* Determine where to insert the node... */
133  if (node == NULL)
134  {
135  /* Allow insertion at the root only in an empty tree */
136  if (BITREEsize(tree) > 0)
137  return -1;
138 
139  position = &tree->root;
140  }
141  else
142  {
143  /* Normally allow insertion only at the end of a branch */
144  if (BITREEright(node) != NULL)
145  return -1;
146 
147  position = &node->right;
148  }
149 
150  /* Allocate storage for the node */
151  if ((new_node = (BiTreeNode)malloc(sizeof(struct BiTreeNode_))) == NULL)
152  return -1;
153 
154  /* Insert the node into the tree */
155  new_node->data = (void *)data;
156  new_node->left = NULL;
157  new_node->right = NULL;
158  *position = new_node;
159 
160  /* Adjust the size of the tree to account for the inserted node */
161  tree->size++;
162 
163  return 0;
164 }
165 
166 int BITREEinsert(BiTree tree, const void *data)
167 {
168  BiTreeNode node, prev;
169  int direction, cmpval;
170 
171  if (!tree->compare) /* User-defined compare-callback NOT set... */
172  return -2;
173 
174  node = BITREEroot(tree); /* Start at the root... */
175  direction = 0;
176 
177  while (!BITREEis_eob(node))
178  {
179  prev = node;
180  cmpval = tree->compare(data, BITREEdata(node));
181 
182  if (cmpval == 0) /* Node found - already in the tree! */
183  return 1; /* Tell caller, that node is already present... */
184  else
185  if (cmpval < 0) /* Go to the left... */
186  {
187  node = BITREEleft(node);
188  direction = 1;
189  }
190  else /* Go to the right... */
191  {
192  node = BITREEright(node);
193  direction = 2;
194  }
195  }
196 
197  if (direction == 0) /* Insert a root node in an empty tree... */
198  return BITREEinsleft(tree, NULL, data);
199 
200  if (direction == 1) /* Insert a new left subnode... */
201  return BITREEinsleft(tree, prev, data);
202 
203  if (direction == 2) /* Insert a new right subnode... */
204  return BITREEinsright(tree, prev, data);
205 
206  return -1; /* Should not get here... */
207 }
208 
209 int BITREElookup(BiTree tree, void **data)
210 {
211  BiTreeNode node;
212  int cmpval;
213 
214  if (!tree->compare) /* User-defined compare-callback NOT set... */
215  return -2;
216 
217  node = BITREEroot(tree); /* Start at the root... */
218 
219  while (!BITREEis_eob(node))
220  {
221  cmpval = tree->compare(*data, BITREEdata(node));
222 
223  if (cmpval == 0) /* Node found! */
224  {
225  *data = BITREEdata(node);
226  return 0;
227  }
228  else
229  if (cmpval < 0)
230  node = BITREEleft(node);
231  else
232  node = BITREEright(node);
233  }
234 
235  return -1; /* Node not found... */
236 }
237 
238 int BITREEremove(BiTree tree, void **data)
239 {
240  int tmp;
241 
242  if ((tmp = BITREElookup(tree, data)) != 0)
243  return tmp;
244  else
245  tree->root = remnode(tree, tree->root, data);
246 
247  return 0; /* Node successfully removed */
248 }
249 
251 {
252  BiTreeNode *position;
253 
254  /* Do not allow removal from an empty tree... */
255  if (BITREEsize(tree) == 0)
256  return;
257 
258  /* Determine where to remove nodes... */
259  if (node == NULL)
260  position = &tree->root;
261  else
262  position = &node->left;
263 
264  /* Remove the nodes... */
265  if (*position != NULL)
266  {
267  BITREEremleft(tree, *position);
268  BITREEremright(tree, *position);
269 
270  if (tree->destroy != NULL)
271  {
272  /* Call a user-defined function to free dynamically allocated data */
273  tree->destroy((*position)->data);
274  }
275 
276  free(*position);
277  *position = NULL;
278 
279  /* Adjust the size of the tree to account for the removed node */
280  tree->size--;
281  }
282 }
283 
285 {
286  BiTreeNode *position;
287 
288  /* Do not allow removal from an empty tree... */
289  if (BITREEsize(tree) == 0)
290  return;
291 
292  /* Determine where to remove nodes... */
293  if (node == NULL)
294  position = &tree->root;
295  else
296  position = &node->right;
297 
298  /* Remove the nodes... */
299  if (*position != NULL)
300  {
301  BITREEremleft(tree, *position);
302  BITREEremright(tree, *position);
303 
304  if (tree->destroy != NULL)
305  {
306  /* Call a user-defined function to free dynamically allocated data */
307  tree->destroy((*position)->data);
308  }
309 
310  free(*position);
311  *position = NULL;
312 
313  /* Adjust the size of the tree to account for the removed node */
314  tree->size--;
315  }
316 }
317 
318 BiTree BITREEmerge(BiTree left_tree, BiTree right_tree, const void *data)
319 {
320  BiTree merge_tree;
321  BiTreeNode node;
322 
323  /* Initialize the merged tree */
324  if ((merge_tree = BITREEinit(left_tree->destroy)) == NULL)
325  return NULL;
326 
327  /* Insert the data for the root node of the merged tree */
328  if (BITREEinsleft(merge_tree, NULL, data) != 0)
329  {
330  BITREEdestroy(merge_tree);
331  return NULL;
332  }
333 
334  /* Merge the two binary trees into a single binary tree */
335  node = BITREEroot(merge_tree);
336  node->left = BITREEroot(left_tree);
337  node->right = BITREEroot(right_tree);
338 
339  /* Adjust the size of the new binary tree */
340  merge_tree->size = merge_tree->size + BITREEsize(left_tree) + BITREEsize(right_tree);
341 
342  /* Do not let the original trees access the merged nodes */
343  left_tree->root = NULL;
344  left_tree->size = 0;
345  right_tree->root = NULL;
346  right_tree->size = 0;
347 
348  return merge_tree;
349 }
350 
352 {
353  return tree->size;
354 }
355 
357 {
358  return tree->root;
359 }
360 
362 {
363  return node == NULL;
364 }
365 
367 {
368  return node->left == NULL && node->right == NULL;
369 }
370 
372 {
373  return node->data;
374 }
375 
377 {
378  return node->left;
379 }
380 
382 {
383  return node->right;
384 }
385 
387 {
388  return treeheight(BITREEroot(tree), 0);
389 }
390 
391 void BITREEprint(BiTree tree, void (*callback)(const void *data))
392 {
393  /* Now - print the entire tree... */
394  printf("\nTREE STATUS: Size(%d nodes)/Height(%d levels) ---\n", BITREEsize(tree), BITREEheight(tree));
395  print_tree(BITREEroot(tree), 0, callback);
396 }
397 
398 void BITREEpreorder(BiTree tree, void (*callback)(const void *data))
399 {
400  preorder(tree->root, callback);
401 }
402 
403 void BITREEinorder(BiTree tree, void (*callback)(const void *data))
404 {
405  inorder(tree->root, callback);
406 }
407 
408 void BITREEpostorder(BiTree tree, void (*callback)(const void *data))
409 {
410  postorder(tree->root, callback);
411 }
412 
413 /* STATIC FUNCTION DEFINITIONS ------------------------------------------ */
414 
415 static BiTreeNode remnode(BiTree tree, BiTreeNode node,
416  void **data)
417 {
418  BiTreeNode ptmp;
419  void *datatmp;
420  int cmpval;
421 
422  if (node != NULL)
423  {
424  /* Compare data */
425  cmpval = tree->compare(*data, node->data);
426 
427  if(cmpval < 0)
428  node->left = remnode(tree, node->left, data);
429  else if (cmpval > 0)
430  node->right = remnode(tree, node->right, data);
431  else if(node->left && node->right) /* Node to be deleted was found - and has 2 children..! */
432  {
433  ptmp = node->right;
434  /* Search for "smallest" node in right subtree - i.e. turn constantly left.. */
435  while (ptmp->left)
436  ptmp = ptmp->left;
437  /* Swap data */
438  datatmp = node->data;
439  node->data = ptmp->data;
440  ptmp->data = datatmp;
441 
442  /* Find and remove the matching node (recursively).. */
443  node->right = remnode(tree, node->right, data);
444  }
445  else /* Matching node has less than 2 children.. */
446  {
447  ptmp = node;
448  assert(ptmp);
449 
450  /* Link over node 'ptmp' */
451  if (node->left == NULL)
452  node = node->right;
453  else if (node->right == NULL)
454  node = node->left;
455  /* Hand node data back to caller */
456  assert(ptmp->data);
457  *data = ptmp->data;
458 
459  free(ptmp);
460  tree->size--;
461  }
462  }
463  return node;
464 }
465 
466 /* --- Function: static void print_tree(BiTree tree, BiTreeNode node, int level, void (*callback)(const void *data)) --- */
467 static void print_tree(BiTreeNode node, int level, void (*callback)(const void *data))
468 {
469  char *p_msk;
470 
471  /* Print current element data */
472  p_msk = (char *)malloc((BITREE_PRINT_LEVEL_PADDING*level+1)*sizeof(char));
473  assert(p_msk);
474  memset(p_msk, '-', BITREE_PRINT_LEVEL_PADDING*level);
475  p_msk[BITREE_PRINT_LEVEL_PADDING*level] = '\0';
476  printf("%s", p_msk);
477  free(p_msk);
478  /* Recursion condition */
479  if (BITREEis_eob(node))
480  {
481  printf("NIL");
482  printf("\n");
483  return;
484  }
485  else
486  callback(BITREEdata(node));
487  printf("\n");
488 
489  /* Recursively traverse and print both "subtrees"... */
490  print_tree(BITREEleft(node), level+1, callback);
491  print_tree(BITREEright(node), level+1, callback);
492 }
493 
494 /* --- Function: void preorder(BiTreeNode node, void (*callback)(const void *data)) --- */
495 static void preorder(BiTreeNode node, void (*callback)(const void *data))
496 {
497  if (node)
498  {
499  /* Handle current node... */
500  callback(node->data);
501  /* Traverse left subtree - recursively in preorder... */
502  preorder(node->left, callback);
503  /* Traverse right subtree - recursively in preorder... */
504  preorder(node->right, callback);
505  }
506 }
507 
508 /* --- Function: void inorder(BiTreeNode node, void (*callback)(const void *data)) --- */
509 static void inorder(BiTreeNode node, void (*callback)(const void *data))
510 {
511  if (node)
512  {
513  /* Traverse left subtree - recursively in inorder... */
514  inorder(node->left, callback);
515  /* Handle current node... */
516  callback(node->data);
517  /* Traverse right subtree - recursively in inorder... */
518  inorder(node->right, callback);
519  }
520 }
521 
522 /* --- Function: void postorder(BiTreeNode node, void (*callback)(const void *data)) --- */
523 static void postorder(BiTreeNode node, void (*callback)(const void *data))
524 {
525  if (node)
526  {
527  /* Traverse left subtree - recursively in postorder... */
528  postorder(node->left, callback);
529  /* Traverse right subtree - recursively in postorder... */
530  postorder(node->right, callback);
531  /* Handle current node... */
532  callback(node->data);
533  }
534 }
535 
536 /* --- Function: int treeheight(BiTreeNode node, int depth) --- */
537 static int treeheight(BiTreeNode node, int depth)
538 {
539  if (!node)
540  return depth;
541  else
542  return maxval(treeheight(node->left, depth+1),
543  treeheight(node->right, depth+1));
544 }