145 lines
4.3 KiB
C
145 lines
4.3 KiB
C
/* This file contains the function implementations for binary trees. */
|
|
#include "binary_tree.h"
|
|
#define TREE_SUCCESS_CODE 0
|
|
#define TREE_FAILURE_CODE 1
|
|
#define TREE_COMPARISON_SMALLER_THAN -1
|
|
#define TREE_COMPARISON_EQUAL_TO 0
|
|
#define TREE_COMPARISON_LARGER_THAN 1
|
|
|
|
/* This function initializes a new empty tree node, will return NULL on failure. */
|
|
tree_node_t* initialize_tree_node() {
|
|
/* Attempt to allocate and return the result. */
|
|
tree_node_t *result = (tree_node_t*) malloc(sizeof(tree_node_t));
|
|
if (result == NULL)
|
|
return NULL;
|
|
result->right = NULL;
|
|
result->left = NULL;
|
|
result->data = NULL;
|
|
return result;
|
|
}
|
|
|
|
/* This function initializes a new tree node and attempts to store the given data within, will return NULL on failure. */
|
|
tree_node_t* initialize_tree_node_store(void *data) {
|
|
/* Attempt to allocate. */
|
|
tree_node_t *result = (tree_node_t*) malloc(sizeof(tree_node_t));
|
|
/* Check, fill and return. */
|
|
if (result == NULL)
|
|
return NULL;
|
|
result->right = NULL;
|
|
result->left = NULL;
|
|
result->data = data;
|
|
return result;
|
|
}
|
|
|
|
/* This function links a node to the right, will overwrite links! Returns 0 on success and 1 on failure. */
|
|
int link_tree_node_right(tree_node_t *parent, tree_node_t *child) {
|
|
/* Sanity check. */
|
|
if (parent == NULL || child == NULL)
|
|
return TREE_FAILURE_CODE;
|
|
/* Link and return success. */
|
|
parent->right = child;
|
|
return TREE_SUCCESS_CODE;
|
|
}
|
|
|
|
/* This function links a node to the left, will overwrite links! Returns 0 on success and 1 on failure. */
|
|
int link_tree_node_left(tree_node_t *parent, tree_node_t *child) {
|
|
/* Sanity check. */
|
|
if (parent == NULL || child == NULL)
|
|
return TREE_FAILURE_CODE;
|
|
/* Link and return success. */
|
|
parent->left = child;
|
|
return TREE_SUCCESS_CODE;
|
|
}
|
|
|
|
/* TODO: rewrite iteratively? */
|
|
/* This function attempts to free a whole tree (recursively), while not touching the data. */
|
|
void free_tree(tree_node_t *root) {
|
|
/* Stopping conditions. */
|
|
if (root == NULL)
|
|
return;
|
|
if (root->right == NULL && root->left == NULL) {
|
|
free(root);
|
|
return;
|
|
}
|
|
/* Recursive case. */
|
|
if (root->right != NULL) {
|
|
free_tree(root->right);
|
|
root->right = NULL;
|
|
}
|
|
if (root->left != NULL) {
|
|
free_tree(root->left);
|
|
root->left = NULL;
|
|
}
|
|
/* Free the current node. */
|
|
free(root);
|
|
}
|
|
|
|
/* TODO: rewrite iteratively? */
|
|
/* This function attempts to free a whole tree (recursively), while using free_function to free the data, if the latter is NULL - will use stdlib free. */
|
|
void free_tree_data(tree_node_t *root, void (*free_function)()) {
|
|
/* Stopping conditions. */
|
|
if (root == NULL)
|
|
return;
|
|
if (root->right == NULL && root->left == NULL) {
|
|
if (free_function == NULL)
|
|
free(root->data);
|
|
else
|
|
free_function(root->data);
|
|
free(root);
|
|
return;
|
|
}
|
|
/* Recursive case. */
|
|
if (root->right != NULL) {
|
|
free_tree_data(root->right);
|
|
root->right = NULL;
|
|
}
|
|
if (root->left != NULL) {
|
|
free_tree_data(root->left);
|
|
root->left = NULL;
|
|
}
|
|
/* Free the current node. */
|
|
if (free_function == NULL)
|
|
free(root->data);
|
|
else
|
|
free_function(root->data);
|
|
free(root);
|
|
}
|
|
|
|
/* Note that the implementation disallows duplication! */
|
|
/* This function inserts data into the tree, will fail on invalid input. Comparison function should return 0 for equal, 1 for larger than and -1 for less than. */
|
|
int insert_node_into_tree(tree_node_t *root, tree_node_t *to_insert, int (*comparison_function)()) {
|
|
/* Local variables. */
|
|
int comparison_result;
|
|
|
|
/* Sanity check. */
|
|
if (comparison_function == NULL || root == NULL)
|
|
return TREE_FAILURE_CODE;
|
|
/* Compare. */
|
|
comparison_result = (*comparison_function)(root->data, to_insert->data);
|
|
/* Check if the value is already there. */
|
|
if (comparison_result == TREE_COMPARISON_EQUAL_TO)
|
|
return TREE_SUCCESS_CODE;
|
|
/* Check if the root is smaller. */
|
|
if (comparison_result == TREE_COMPARISON_SMALLER_THAN) {
|
|
/* The root is smaller. */
|
|
if (root->right == NULL) {
|
|
/* Insert to the right. */
|
|
root->right = to_insert;
|
|
return TREE_SUCCESS_CODE;
|
|
}
|
|
/* Recurse. */
|
|
return insert_node_into_tree(root->right, to_insert, comparison_function);
|
|
} else {
|
|
/* The root is larger. */
|
|
if (root->left == NULL) {
|
|
/* Insert to the left. */
|
|
root->right = to_insert;
|
|
return TREE_SUCCESS_CODE;
|
|
}
|
|
/* Recurse. */
|
|
return insert_node_into_tree(root->left, to_insert, comparison_function);
|
|
}
|
|
/* Shouldn't ever reach here! */
|
|
return TREE_FAILURE_CODE;
|
|
}
|