Updated binary search trees much like binary trees (check previous commit), but still need to write tests thereof.
This commit is contained in:
parent
ece6520a94
commit
4c9511ab78
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue