Updated binary tree, better debug flow and faster non-debug builds, with added const and inline optimizations where applicable.
This commit is contained in:
parent
023b14e194
commit
ece6520a94
|
@ -223,8 +223,8 @@ int test_trees() {
|
|||
/* Print result. */
|
||||
printf(TEST_INITIALIZE_TREE_NODE_STORE_SUCCESS);
|
||||
/* Link the left and right nodes. */
|
||||
assert(link_tree_node_right(root, right) == 0);
|
||||
assert(link_tree_node_left(root, left) == 0);
|
||||
link_tree_node_right(root, right);
|
||||
link_tree_node_left(root, left);
|
||||
assert(root->right == right);
|
||||
assert(root->left == left);
|
||||
/* Print result. */
|
||||
|
@ -262,7 +262,7 @@ int test_trees() {
|
|||
while (left->right != NULL)
|
||||
left = left->right;
|
||||
/* Attach the node. */
|
||||
assert(insert_node_into_tree(root, right, comparison_function_int) == TREE_SUCCESS_CODE);
|
||||
insert_node_into_tree(root, right, comparison_function_int);
|
||||
assert(left->right == right);
|
||||
/* Cleanup. */
|
||||
free_tree(root);
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
#include "binary_tree.h"
|
||||
|
||||
/* This function initializes a new empty tree node, will return NULL on failure. */
|
||||
tree_node_t* initialize_tree_node() {
|
||||
static inline 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)
|
||||
if (!result)
|
||||
return NULL;
|
||||
result->right = NULL;
|
||||
result->left = NULL;
|
||||
|
@ -30,11 +30,11 @@ tree_node_t* 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_tree_node_store(void *data) {
|
||||
static inline 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)
|
||||
if (!result)
|
||||
return NULL;
|
||||
result->right = NULL;
|
||||
result->left = NULL;
|
||||
|
@ -42,42 +42,39 @@ tree_node_t* initialize_tree_node_store(void *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) {
|
||||
/* This function links a node to the right, will overwrite links! */
|
||||
static inline void link_tree_node_right(tree_node_t *parent, tree_node_t* const child) {
|
||||
/* Sanity check. */
|
||||
if (parent == NULL || child == NULL)
|
||||
return TREE_FAILURE_CODE;
|
||||
/* Link and return success. */
|
||||
assert(parent && child);
|
||||
|
||||
/* Link. */
|
||||
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) {
|
||||
/* This function links a node to the left, will overwrite links! */
|
||||
static inline void link_tree_node_left(tree_node_t *parent, tree_node_t* const child) {
|
||||
/* Sanity check. */
|
||||
if (parent == NULL || child == NULL)
|
||||
return TREE_FAILURE_CODE;
|
||||
/* Link and return success. */
|
||||
assert(parent && child);
|
||||
|
||||
/* Link. */
|
||||
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) {
|
||||
static inline void free_tree(tree_node_t *root) {
|
||||
/* Stopping conditions. */
|
||||
if (root == NULL)
|
||||
if (!root)
|
||||
return;
|
||||
if (root->right == NULL && root->left == NULL) {
|
||||
if (!(root->right) && !(root->left)) {
|
||||
free(root);
|
||||
return;
|
||||
}
|
||||
/* Recursive case. */
|
||||
if (root->right != NULL) {
|
||||
if (root->right) {
|
||||
free_tree(root->right);
|
||||
root->right = NULL;
|
||||
}
|
||||
if (root->left != NULL) {
|
||||
if (root->left) {
|
||||
free_tree(root->left);
|
||||
root->left = NULL;
|
||||
}
|
||||
|
@ -85,14 +82,13 @@ void free_tree(tree_node_t *root) {
|
|||
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)(const void*)) {
|
||||
static inline void free_tree_data(tree_node_t *root, void (*free_function)(const void*)) {
|
||||
/* Stopping conditions. */
|
||||
if (root == NULL)
|
||||
if (!root)
|
||||
return;
|
||||
if (root->right == NULL && root->left == NULL) {
|
||||
if (free_function == NULL)
|
||||
if (!(root->right) && !(root->left)) {
|
||||
if (!free_function)
|
||||
free(root->data);
|
||||
else
|
||||
free_function(root->data);
|
||||
|
@ -100,16 +96,16 @@ void free_tree_data(tree_node_t *root, void (*free_function)(const void*)) {
|
|||
return;
|
||||
}
|
||||
/* Recursive case. */
|
||||
if (root->right != NULL) {
|
||||
if (root->right) {
|
||||
free_tree_data(root->right, free_function);
|
||||
root->right = NULL;
|
||||
}
|
||||
if (root->left != NULL) {
|
||||
if (root->left) {
|
||||
free_tree_data(root->left, free_function);
|
||||
root->left = NULL;
|
||||
}
|
||||
/* Free the current node. */
|
||||
if (free_function == NULL)
|
||||
if (!free_function)
|
||||
free(root->data);
|
||||
else
|
||||
free_function(root->data);
|
||||
|
@ -118,49 +114,47 @@ void free_tree_data(tree_node_t *root, void (*free_function)(const void*)) {
|
|||
|
||||
/* 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)(const void*, const void*)) {
|
||||
static inline void insert_node_into_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 (comparison_function == NULL || root == NULL)
|
||||
return TREE_FAILURE_CODE;
|
||||
assert(comparison_function && root);
|
||||
|
||||
/* 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_tree(root->right, to_insert, comparison_function);
|
||||
insert_node_into_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;
|
||||
root->left = to_insert;
|
||||
return;
|
||||
}
|
||||
/* Recurse. */
|
||||
return insert_node_into_tree(root->left, to_insert, comparison_function);
|
||||
insert_node_into_tree(root->left, to_insert, comparison_function);
|
||||
}
|
||||
/* Shouldn't ever reach here! */
|
||||
return TREE_FAILURE_CODE;
|
||||
}
|
||||
|
||||
/* This function finds the tree's depth (at the deepest leaf). */
|
||||
size_t find_tree_depth(tree_node_t *root) {
|
||||
static inline size_t find_tree_depth(const tree_node_t * const root) {
|
||||
/* Simple case. */
|
||||
if (root == NULL)
|
||||
return 0;
|
||||
if (!root)
|
||||
return ((size_t)0L);
|
||||
|
||||
/* Recurse and return the largest value. */
|
||||
return 1 + max(find_tree_depth(root->left), find_tree_depth(root->right));
|
||||
return ((size_t)1L) + max(find_tree_depth(root->left), find_tree_depth(root->right));
|
||||
}
|
||||
|
|
|
@ -18,8 +18,18 @@
|
|||
#include <stdlib.h>
|
||||
#ifndef BINARY_TREE_H
|
||||
#define BINARY_TREE_H
|
||||
/* Include assert.h to allow code generation, but only run with debug flag. */
|
||||
#ifdef DEBUG
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif /* NDEBUG. */
|
||||
#endif /* DEBUG. */
|
||||
#include <assert.h>
|
||||
#include "../../nodes/tree_node.h"
|
||||
|
||||
/* Max macro, for use within the depth function. */
|
||||
#include "../../utils/max_macro.h"
|
||||
|
||||
/* Define constants. */
|
||||
/* Return code for success. */
|
||||
#define TREE_SUCCESS_CODE 0
|
||||
|
@ -32,27 +42,21 @@
|
|||
/* Return code for comparison, larger. */
|
||||
#define TREE_COMPARISON_LARGER_THAN 1
|
||||
|
||||
/* Define a max macro for use within the depth function. */
|
||||
#define max(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
||||
|
||||
/* Define all the functions. */
|
||||
/* This function initializes a single node. */
|
||||
tree_node_t* initialize_tree_node();
|
||||
static inline tree_node_t* initialize_tree_node();
|
||||
/* This function initializes a single node and attempts to store the given data within. */
|
||||
tree_node_t* initialize_tree_node_store(void *data);
|
||||
static inline tree_node_t* initialize_tree_node_store(void *data);
|
||||
/* This function links a node to the right. */
|
||||
int link_tree_node_right(tree_node_t *parent, tree_node_t *child);
|
||||
static inline void link_tree_node_right(tree_node_t *parent, tree_node_t* const child);
|
||||
/* This function links a node to the left. */
|
||||
int link_tree_node_left(tree_node_t *parent, tree_node_t *child);
|
||||
static inline void link_tree_node_left(tree_node_t *parent, tree_node_t* const child);
|
||||
/* This function frees a whole tree - not including data. */
|
||||
void free_tree(tree_node_t *root);
|
||||
static inline void free_tree(tree_node_t *root);
|
||||
/* This function frees a whole tree, including data. */
|
||||
void free_tree_data(tree_node_t *root, void (*free_function)(const void*));
|
||||
static inline void free_tree_data(tree_node_t *root, void (*free_function)(const void*));
|
||||
/* This function inserts data to the tree. */
|
||||
int insert_node_into_tree(tree_node_t *root, tree_node_t *to_insert, int (*comparison_function)(const void*, const void*));
|
||||
static inline void insert_node_into_tree(tree_node_t *root, tree_node_t* const to_insert, int (*comparison_function)(const void*, const void*));
|
||||
/* This function finds the tree's depth (at the deepest leaf). */
|
||||
size_t find_tree_depth(tree_node_t *root);
|
||||
static inline size_t find_tree_depth(const tree_node_t * const root);
|
||||
#endif /* BINARY_TREE_H */
|
||||
|
|
Loading…
Reference in New Issue