1
0
Fork 0

Updated binary search trees much like binary trees (check previous commit), but still need to write tests thereof.

This commit is contained in:
wael 2022-03-05 22:05:09 +02:00
parent ece6520a94
commit 4c9511ab78
No known key found for this signature in database
GPG Key ID: C0A5FBF4558963D4
2 changed files with 81 additions and 131 deletions

View File

@ -24,30 +24,33 @@
#include "binary_search_tree.h"
/* This function initializes a new empty tree node, will return NULL on failure. */
tree_node_t* initialize_binary_search_tree_node() {
static inline tree_node_t* initialize_binary_search_tree_node() {
/* Delegate internally. */
return initialize_tree_node();
}
/* This function initializes a new tree node and attempts to store the given data within, will return NULL on failure. */
tree_node_t* initialize_binary_search_tree_node_store(void *data) {
static inline tree_node_t* initialize_binary_search_tree_node_store(void* const data) {
/* Delegate internally. */
return initialize_tree_node_store(data);
}
/* This function is used to recursively fill an array into a BST. */
tree_node_t* initialize_binary_search_tree_recursive(void **array, int index_start, int index_end) {
static inline tree_node_t* initialize_binary_search_tree_recursive(void** const array, size_t index_start, size_t index_end) {
/* Sanity check. */
assert(array);
/* Local variables. */
int middle_index;
size_t middle_index;
tree_node_t *root;
/* Calculate the middle index. */
middle_index = index_start + index_end;
middle_index /= 2;
middle_index /= ((size_t)2L);
/* Allocate the node. */
root = (tree_node_t*) malloc(sizeof(tree_node_t));
if (root == NULL)
if (!root)
return NULL;
/* Set the value. */
@ -65,142 +68,95 @@ tree_node_t* initialize_binary_search_tree_recursive(void **array, int index_sta
root->right = initialize_binary_search_tree_recursive(array, middle_index, index_end);
root->left = initialize_binary_search_tree_recursive(array, index_start, middle_index);
/* Check if allocation failed in any of the recursive cases. */
if (!(root->right) || !(root->left)) {
free(root->right);
free(root->left);
return NULL;
}
/* Return the node. */
return root;
}
/* This function creates a BST for a sorted array. */
tree_node_t* initialize_binary_search_tree(void **array, int length) {
static inline tree_node_t* initialize_binary_search_tree(void** const array, size_t length) {
/* Sanity check. */
if (array == NULL || length == 0)
return NULL;
assert(array && length);
/* Delegate. */
return initialize_binary_search_tree_recursive(array, 0, length - 1);
}
/* This function links a node to the right, will overwrite links! Returns 0 on success and 1 on failure. */
int link_binary_search_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 right, will overwrite links!. */
static inline void link_binary_search_tree_node_right(tree_node_t *parent, tree_node_t* const child) {
/* Delegate. */
link_tree_node_right(parent, child);
}
/* This function links a node to the left, will overwrite links! Returns 0 on success and 1 on failure. */
int link_binary_search_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;
/* This function links a node to the left, will overwrite links!. */
static inline void link_binary_search_tree_node_left(tree_node_t *parent, tree_node_t* const child) {
/* Delegate. */
link_tree_node_left(parent, child);
}
/* TODO: rewrite iteratively? */
/* This function attempts to free a whole tree (recursively), while not touching the data. */
void free_binary_search_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_binary_search_tree(root->right);
root->right = NULL;
}
if (root->left != NULL) {
free_binary_search_tree(root->left);
root->left = NULL;
}
/* Free the current node. */
free(root);
static inline void free_binary_search_tree(tree_node_t *root) {
/* Delegate. */
free_tree(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_binary_search_tree_data(tree_node_t *root, void (*free_function)(const void*)) {
/* 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_binary_search_tree_data(root->right, free_function);
root->right = NULL;
}
if (root->left != NULL) {
free_binary_search_tree_data(root->left, free_function);
root->left = NULL;
}
/* Free the current node. */
if (free_function == NULL)
free(root->data);
else
free_function(root->data);
free(root);
static inline void free_binary_search_tree_data(tree_node_t *root, void (*free_function)(const void*)) {
/* Delegate. */
free_tree_data(tree, free_function);
}
/* 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_binary_search_tree(tree_node_t *root, tree_node_t *to_insert, int (*comparison_function)(const void*, const void*)) {
/* This function inserts data into the tree, will silently fail on invalid input. Comparison function should return 0 for equal, 1 for larger than and -1 for less than. */
static inline void insert_node_into_binary_search_tree(tree_node_t *root, tree_node_t* const to_insert, int (*comparison_function)(const void*, const void*)) {
/* Local variables. */
int comparison_result;
/* Sanity check. */
if (root == NULL || comparison_function == NULL)
return TREE_FAILURE_CODE;
assert(root && comparison_function);
/* 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;
return;
/* Check if the root is smaller. */
if (comparison_result == TREE_COMPARISON_SMALLER_THAN) {
/* The root is smaller. */
if (root->right == NULL) {
if (!(root->right)) {
/* Insert to the right. */
root->right = to_insert;
return TREE_SUCCESS_CODE;
return;
}
/* Recurse. */
return insert_node_into_binary_search_tree(root->right, to_insert, comparison_function);
} else {
/* The root is larger. */
if (root->left == NULL) {
if (!(root->left)) {
/* Insert to the left. */
root->right = to_insert;
return TREE_SUCCESS_CODE;
return;
}
/* Recurse. */
return insert_node_into_binary_search_tree(root->left, to_insert, comparison_function);
}
/* Shouldn't ever reach here! */
return TREE_FAILURE_CODE;
}
/* This function searches for data in the tree. */
/* 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. */
tree_node_t* search_in_binary_search_tree(tree_node_t *root, void *data, int (*comparison_function)(const void*, const void*)) {
static inline tree_node_t* search_in_binary_search_tree(const tree_node_t* const root, const void* const data, int (*comparison_function)(const void*, const void*)) {
/* Local variables. */
int comparison_result;
/* Sanity check. */
if (root == NULL || comparison_function == NULL)
return NULL;
assert(root && comparison_function);
/* Check if we found the right node, and recurse accordingly. */
comparison_result = (*comparison_function)(root->data, data);
@ -208,57 +164,55 @@ tree_node_t* search_in_binary_search_tree(tree_node_t *root, void *data, int (*c
}
/* This function finds the tree's depth (at the deepest leaf). */
size_t find_binary_search_tree_depth(tree_node_t *root) {
static inline size_t find_binary_search_tree_depth(const tree_node_t* const root) {
/* Delegate. */
return find_tree_depth(root);
}
/* This function fills an array in a sorted manner with the values from a BST. */
/* Takes the tree's root, the array to fill, a pointer to the current fill index, and a pointer to the array's maximal length. */
/* This function fills an allocated array in a sorted manner with the values from a BST. */
/* Takes the tree's root, the array to fill, a pointer to the current fill index, and a value of the array's maximal length. */
/* Doesn't do much sanity checking on the input, returns defined constants on failure/success. */
int fill_array_binary_search_tree(tree_node_t *root, void **array, size_t *index, size_t length) {
/* Local variables. */
int flag_right, flag_left;
/* Initialize. */
flag_right = BINARY_SEARCH_TREE_SUCCESS_CODE;
flag_left = BINARY_SEARCH_TREE_SUCCESS_CODE;
static inline void fill_array_binary_search_tree(tree_node_t *root, void **array, size_t *index, const size_t length) {
/* Sanity check. */
if (root == NULL || array == NULL || *index < 0 || *index >= length)
return BINARY_SEARCH_TREE_FAILURE_CODE;
assert(root && array);
/* Stopping condition. */
if (*index >= length)
return;
/* Check if we have reached a leaf. */
if (root->left == NULL && root->right == NULL) {
if (!(root->left) && !(root->right)) {
/* Insert into the array, and advance. */
array[*index] = root->data;
(*index)++;
return BINARY_SEARCH_TREE_SUCCESS_CODE;
return;
}
/* Non-leaf node. */
/* Recurse to the left, add the current node's data, and then recurse to the right. */
/* Left. */
if (root->left != NULL)
flag_right = fill_array_binary_search_tree(root->left, array, index, length);
if (root->left)
fill_array_binary_search_tree(root->left, array, index, length);
/* Check the length. */
if (*index >= length)
return;
/* Current. */
array[*index] = root->data;
(*index)++;
/* Check the length. */
if (*index >= length)
return;
/* Right. */
if (root->right != NULL)
flag_left = fill_array_binary_search_tree(root->right, array, index, length);
/* Done - Check if the flags are equal and successful, return accordingly (fail if one is false). */
return (flag_right == flag_left && flag_right == BINARY_SEARCH_TREE_SUCCESS_CODE) ? BINARY_SEARCH_TREE_SUCCESS_CODE : BINARY_SEARCH_TREE_FAILURE_CODE;
fill_array_binary_search_tree(root->right, array, index, length);
}
/* This function creates a sorted array, from a binary search tree. */
/* Sets the resize status accodrdingly (in case it failed or not). */
/* Returns a pointer to the first cell in the array on success, NULL on failure. */
void **sorted_array_from_binary_search_tree(tree_node_t *root, size_t *length, int *resize_status) {
static inline void **sorted_array_from_binary_search_tree(tree_node_t *root, size_t *length, int *resize_status) {
/* Sanity check. */
if (root == NULL || length == NULL)
return NULL;
assert(root && length);
/* Local variables. */
size_t height, array_size, index;
@ -276,23 +230,19 @@ void **sorted_array_from_binary_search_tree(tree_node_t *root, size_t *length, i
/* Attempt to allocate the array. */
array = (void**) calloc(array_size, sizeof(void*));
/* Check for allocation failures. */
if (array == NULL)
if (!array)
return NULL;
/* Try to fill. */
index = 0;
/* Delegate. */
if (fill_array_binary_search_tree(root, array, &index, array_size) == BINARY_SEARCH_TREE_FAILURE_CODE) {
/* Failed! Free and return NULL. */
free(array);
return NULL;
}
fill_array_binary_search_tree(root, array, &index, array_size);
/* Set the array's length. */
*length = ++index;
*length = index;
/* Resize the array if needed. */
if (index < array_size) {
/* Check for (non-fatal) failure. */
if (reallocarray(array, index, sizeof(void*)) == NULL && errno == ENOMEM)
if (!reallocarray(array, index, sizeof(void*)) && errno == ENOMEM)
*resize_status = FALSE;
else
*resize_status = TRUE;

View File

@ -38,29 +38,29 @@
/* Define all the functions. */
/* This function initializes a single node. */
tree_node_t* initialize_binary_search_tree_node();
static inline tree_node_t* initialize_binary_search_tree_node();
/* This function initializes a single node and attempts to store the given data within. */
tree_node_t* initialize_binary_search_tree_node_store(void *data);
static inline tree_node_t* initialize_binary_search_tree_node_store(void* const data);
/* This helper function is used to recursively fill an array into a BST. */
tree_node_t* initialize_binary_search_tree_recursive(void **array, int index_start, int index_end);
static inline tree_node_t* initialize_binary_search_tree_recursive(void** const array, size_t index_start, size_t index_end);
/* This function creates a BST for a sorted array. */
tree_node_t* initialize_binary_search_tree(void **array, int length);
static inline tree_node_t* initialize_binary_search_tree(void** const array, size_t length);
/* This function links a node to the right. */
int link_binary_search_tree_node_right(tree_node_t *parent, tree_node_t *child);
static inline link_binary_search_tree_node_right(tree_node_t *parent, tree_node_t *child);
/* This function links a node to the left. */
int link_binary_search_tree_node_left(tree_node_t *parent, tree_node_t *child);
static inline link_binary_search_tree_node_left(tree_node_t *parent, tree_node_t *child);
/* This function frees a whole tree - not including data. */
void free_binary_search_tree(tree_node_t *root);
static inline void free_binary_search_tree(tree_node_t *root);
/* This function frees a whole tree, including data. */
void free_binary_search_tree_data(tree_node_t *root, void (*free_function)(const void*));
static inline void free_binary_search_tree_data(tree_node_t *root, void (*free_function)(const void*));
/* This function inserts data to the tree. */
int insert_node_into_binary_search_tree(tree_node_t *root, tree_node_t *to_insert, int (*comparison_function)(const void*, const void*));
static inline void insert_node_into_binary_search_tree(tree_node_t *root, tree_node_t *to_insert, int (*comparison_function)(const void*, const void*));
/* This function searches for data in the tree. */
tree_node_t* search_in_binary_search_tree(tree_node_t *root, void *data, int (*comparison_function)(const void*, const void*));
static inline tree_node_t* search_in_binary_search_tree(const tree_node_t* const root, const void* const data, int (*comparison_function)(const void*, const void*));
/* This function finds the tree's depth (at the deepest leaf). */
size_t find_binary_search_tree_depth(tree_node_t *root);
static inline size_t find_binary_search_tree_depth(const tree_node_t* const root);
/* This function fills a binary search tree into an allocated array. */
int fill_array_binary_search_tree(tree_node_t *root, void **array, size_t *index, size_t length);
static inline void fill_array_binary_search_tree(tree_node_t *root, void **array, size_t *index, const size_t length);
/* This function creates a sorted array, from a binary search tree. */
void **sorted_array_from_binary_search_tree(tree_node_t *root, size_t *length, int *resize_status);
static inline void **sorted_array_from_binary_search_tree(tree_node_t *root, size_t *length, int *resize_status);
#endif /* BINARY_SEARCH_TREE_H */