1
0
Fork 0

Updated binary tree, better debug flow and faster non-debug builds, with added const and inline optimizations where applicable.

This commit is contained in:
wael 2022-03-05 19:27:21 +02:00
parent 023b14e194
commit ece6520a94
No known key found for this signature in database
GPG Key ID: C0A5FBF4558963D4
3 changed files with 61 additions and 63 deletions

View File

@ -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);

View File

@ -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));
}

View File

@ -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 */