Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Onto AVL trees! in ch9 of mastering algos with C
- Loading branch information
Showing
6 changed files
with
359 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <stdio.h> | ||
#include "bitree.h" | ||
|
||
|
||
void bitree_init(BiTree *tree, void (*destroy)(void *data)) { | ||
tree->size = 0; | ||
tree->destroy = destroy; | ||
tree->root = NULL; | ||
return; | ||
} | ||
|
||
|
||
void bitree_destroy(BiTree *tree) { | ||
/* Remove all the nodes from the tree */ | ||
bitree_rem_left(tree, NULL); | ||
memset(tree, 0, sizeof(BiTree)); | ||
return; | ||
} | ||
|
||
|
||
int bitree_ins_left(BiTree *tree, BiTreeNode *node, const void *data) { | ||
BiTreeNode *new_node, **position; | ||
|
||
/* Determine where to insert the node */ | ||
if (node == NULL) { | ||
/* Allow insertion at the root only in an empty tree */ | ||
if (bitree_size(tree) > 0) | ||
return -1; | ||
position = &tree->root; | ||
} else { | ||
/* Normally allow insertion only at the end of a branch */ | ||
if (bitree_left(node) != NULL) | ||
return -1; | ||
position = &node->left; | ||
} | ||
|
||
/* Allocate storage for the node */ | ||
if ((new_node = (BiTreeNode *) malloc(sizeof(BiTreeNode))) == NULL) | ||
return -1; | ||
|
||
/* Insert node into tree */ | ||
new_node->data = (void *) data; | ||
new_node->left = NULL; | ||
new_node->right = NULL; | ||
*position = new_node; | ||
|
||
/* Adjust the size of the tree to account for the inserted node */ | ||
tree->size++; | ||
return 0; | ||
} | ||
|
||
|
||
int bitree_ins_right(BiTree *tree, BiTreeNode *node, const void *data) { | ||
BiTreeNode *new_node, **position; | ||
|
||
/* Determine where to insert the node */ | ||
if (node == NULL) { | ||
/* Allow insertion at the root only in an empty tree */ | ||
if (bitree_size(tree) > 0) | ||
return -1; | ||
position = &tree->root; | ||
} else { | ||
/* Normally allow insertion only at the end of a branch */ | ||
if (bitree_right(node) != NULL) | ||
return -1; | ||
position = &node->right; | ||
} | ||
|
||
/* Allocate storage for the node */ | ||
if ((new_node = (BiTreeNode *) malloc(sizeof(BiTreeNode))) == NULL) | ||
return -1; | ||
|
||
/* Insert node into tree */ | ||
new_node->data = (void *) data; | ||
new_node->left = NULL; | ||
new_node->right = NULL; | ||
*position = new_node; | ||
|
||
/* Adjust the size of the tree to account for the inserted node */ | ||
tree->size++; | ||
return 0; | ||
} | ||
|
||
|
||
void bitree_rem_left(BiTree *tree, BiTreeNode *node) { | ||
BiTreeNode **position; | ||
|
||
if (bitree_size(tree) == 0) | ||
return; | ||
|
||
/* Determine where to remove nodes */ | ||
if (node == NULL) | ||
position = &tree->root; | ||
else | ||
position = &node->left; | ||
|
||
/* Remove the nodes */ | ||
if (*position != NULL) { | ||
bitree_rem_left(tree, *position); | ||
bitree_rem_right(tree, *position); | ||
|
||
if (tree->destroy != NULL) { | ||
/* Call user-defined function to free dynamically allocated data */ | ||
tree->destroy((*position)->data); | ||
} | ||
|
||
free(*position); | ||
*position = NULL; | ||
tree->size--; | ||
} | ||
|
||
return; | ||
} | ||
|
||
|
||
void bitree_rem_right(BiTree *tree, BiTreeNode *node) { | ||
BiTreeNode **position; | ||
|
||
if (bitree_size(tree) == 0) | ||
return; | ||
|
||
/* Determine where to remove nodes */ | ||
if (node == NULL) | ||
position = &tree->root; | ||
else | ||
position = &node->right; | ||
|
||
/* Remove the nodes */ | ||
if (*position != NULL) { | ||
bitree_rem_left(tree, *position); | ||
bitree_rem_right(tree, *position); | ||
|
||
if (tree->destroy != NULL) { | ||
/* Call user-defined function to free dynamically allocated data */ | ||
tree->destroy((*position)->data); | ||
} | ||
|
||
free(*position); | ||
*position = NULL; | ||
tree->size--; | ||
} | ||
|
||
return; | ||
} | ||
|
||
|
||
int bitree_merge(BiTree *merge, BiTree *left, BiTree *right, const void *data) { | ||
/* Initialize the merged tree */ | ||
bitree_init(merge, left->destroy); | ||
|
||
if (bitree_ins_left(merge, NULL, data) != 0) { | ||
bitree_destroy(merge); | ||
return -1; | ||
} | ||
|
||
/* Merge the two binary trees into a single binary tree */ | ||
bitree_root(merge)->left = bitree_root(left); | ||
bitree_root(merge)->right = bitree_root(right); | ||
|
||
merge->size = merge->size + bitree_size(left) + bitree_size(right); | ||
|
||
/* Don't left original trees access merged nodes */ | ||
left->root = NULL; | ||
left->size = 0; | ||
right->root = NULL; | ||
right->size = 0; | ||
|
||
return 0; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#ifndef BITREE_H | ||
#define BITREE_H | ||
|
||
#include <stdlib.h> | ||
|
||
|
||
typedef struct BiTreeNode_ { | ||
void *data; | ||
struct BiTreeNode_ *left; | ||
struct BiTreeNode_ *right; | ||
} BiTreeNode; | ||
|
||
|
||
typedef struct BiTree_ { | ||
int size; | ||
int (*compare)(const void *key1, const void *key2); | ||
void (*destroy)(void *data); | ||
BiTreeNode *root; | ||
} BiTree; | ||
|
||
|
||
void bitree_init(BiTree *tree, void (*destroy)(void *data)); | ||
void bitree_destroy(BiTree *tree); | ||
int bitree_ins_left(BiTree *tree, BiTreeNode *node, const void *data); | ||
int bitree_ins_right(BiTree *tree, BiTreeNode *node, const void *data); | ||
void bitree_rem_left(BiTree *tree, BiTreeNode *node); | ||
void bitree_rem_right(BiTree *tree, BiTreeNode *node); | ||
int bitree_merge(BiTree *merge, BiTree *left, BiTree *right, const void *data); | ||
#define bitree_size(tree) ((tree)->size) | ||
#define bitree_root(tree) ((tree)->root) | ||
#define bitree_is_eob(tree) ((node) == NULL) | ||
#define bitree_is_leaf(tree) ((node)->left == NULL && (node)->right == NULL) | ||
#define bitree_data(node) ((node)->data) | ||
#define bitree_left(node) ((node)->left) | ||
#define bitree_right(node) ((node)->right) | ||
#endif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#include <stdio.h> | ||
#include "bitree.h" | ||
|
||
|
||
int main() { | ||
BiTree tree; | ||
BiTreeNode *node; | ||
|
||
int data1 = 5; | ||
int data2 = 3; | ||
int data3 = 8; | ||
int data4 = 1; | ||
|
||
bitree_init(&tree, free); | ||
bitree_ins_left(&tree, NULL, &data1); | ||
bitree_ins_left(&tree, bitree_root(&tree), &data2); | ||
bitree_ins_right(&tree, bitree_root(&tree), &data3); | ||
bitree_ins_left(&tree, bitree_root(&tree)->left, &data4); | ||
|
||
for (node = bitree_root(&tree); node != NULL; node = bitree_left(node)) { | ||
printf("%d\n", *((int *) bitree_data(node))); | ||
} | ||
|
||
return 0; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#include <stdio.h> | ||
#include "../ch5/list.h" | ||
#include "traverse.h" | ||
|
||
|
||
int preorder(const BiTreeNode *node, List *list) { | ||
if (!bitree_is_eob(node)) { | ||
if (list_ins_next(list, list_tail(list), bitree_data(node)) != 0) | ||
return -1; | ||
|
||
if (!bitree_is_eob(bitree_left(node))) | ||
if (preorder(bitree_left(node), list) != 0) | ||
return -1; | ||
|
||
if (!bitree_is_eob(bitree_right(node))) | ||
if (preorder(bitree_right(node), list) != 0) | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
|
||
int inorder(const BiTreeNode *node, List *list) { | ||
if (!bitree_is_eob(node)) { | ||
if (!bitree_is_eob(bitree_left(node))) | ||
if (inorder(bitree_left(node), list) != 0) | ||
return -1; | ||
|
||
if (list_ins_next(list, list_tail(list), bitree_data(node)) != 0) | ||
return -1; | ||
|
||
if (!bitree_is_eob(bitree_right(node))) | ||
if (inorder(bitree_right(node), list) != 0) | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
|
||
int postorder(const BiTreeNode *node, List *list) { | ||
if (!bitree_is_eob(node)) { | ||
if (!bitree_is_eob(bitree_left(node))) | ||
if (postorder(bitree_left(node), list) != 0) | ||
return -1; | ||
|
||
if (!bitree_is_eob(bitree_right(node))) | ||
if (postorder(bitree_right(node), list) != 0) | ||
return -1; | ||
|
||
if (list_ins_next(list, list_tail(list), bitree_data(node)) != 0) | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#include "bitree.h" | ||
|
||
int preorder(const BiTreeNode *node, List *list); | ||
int inorder(const BiTreeNode *node, List *list); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#include <stdio.h> | ||
#include "../ch5/list.h" | ||
#include "traverse.h" | ||
|
||
|
||
int main() { | ||
BiTree tree; | ||
List list; | ||
ListElmt *node; | ||
|
||
int data1 = 5; | ||
int data2 = 3; | ||
int data3 = 8; | ||
int data4 = 1; | ||
int data5 = 4; | ||
int data6 = 2; | ||
int data7 = 7; | ||
|
||
bitree_init(&tree, free); | ||
bitree_ins_left(&tree, NULL, &data1); | ||
bitree_ins_left(&tree, bitree_root(&tree), &data2); | ||
bitree_ins_right(&tree, bitree_root(&tree), &data3); | ||
bitree_ins_left(&tree, bitree_root(&tree)->left, &data4); | ||
bitree_ins_right(&tree, bitree_root(&tree)->left, &data5); | ||
bitree_ins_left(&tree, bitree_root(&tree)->left->right, &data6); | ||
bitree_ins_left(&tree, bitree_root(&tree)->right, &data7); | ||
|
||
list_init(&list, NULL); | ||
if (preorder(bitree_root(&tree), &list) != 0) { | ||
printf("preorder traversal failed\n"); | ||
return -1; | ||
} | ||
printf("preorder traversal:\n"); | ||
for (node = list_head(&list); node != NULL; node = list_next(node)) { | ||
printf("%d\n", *((int *) list_data(node))); | ||
} | ||
|
||
list_destroy(&list); | ||
list_init(&list, NULL); | ||
if (inorder(bitree_root(&tree), &list) != 0) { | ||
printf("inorder traversal failed\n"); | ||
return -1; | ||
} | ||
printf("\ninorder traversal:\n"); | ||
for (node = list_head(&list); node != NULL; node = list_next(node)) { | ||
printf("%d\n", *((int *) list_data(node))); | ||
} | ||
|
||
list_destroy(&list); | ||
list_init(&list, NULL); | ||
if (postorder(bitree_root(&tree), &list) != 0) { | ||
printf("postorder traversal failed\n"); | ||
return -1; | ||
} | ||
printf("\npostorder traversal:\n"); | ||
for (node = list_head(&list); node != NULL; node = list_next(node)) { | ||
printf("%d\n", *((int *) list_data(node))); | ||
} | ||
|
||
return 0; | ||
} | ||
|