commit 72f3ae316499fcb77fd19692046a938007023271 Author: wael Date: Sun Aug 29 17:26:31 2021 +0300 Initial Commit diff --git a/linked_lists/double_linked_list.h b/linked_lists/double_linked_list.h new file mode 100644 index 0000000..3c9d00a --- /dev/null +++ b/linked_lists/double_linked_list.h @@ -0,0 +1,70 @@ +/* This header defines a single-linked-list and related functions. */ +/* Use the single nodes. */ +#include +#ifndef DOUBLE_LINKED_LIST_H +#define DOUBLE_LINKED_LIST_H +#include "../nodes/double_node.h" + +/* Constants. */ +#define SUCCESS_CODE_DOUBLE_LINKED_LIST_C 1 +#define FAILURE_CODE_DOUBLE_LINKED_LIST_C 0 +#define INDEX_NOT_FOUND_CODE_LINKED_LIST_C -1 +#define INVALID_INPUT_CODE_LINKED_LIST_C -2 +#define CODE_FREE_SUCCESS_MALFORMED_LINKED_LIST_C -1 +#define INDEX_HEAD_LINKED_LIST_C 0 + +/* The actual linked list struct. */ +typedef struct double_linked_list { + /* Stores the list's length. */ + int length; + /* Stores the head node pointer. */ + double_node_t *head; + /* Stores the tail node pointer. */ + double_node_t *tail; +} double_linked_list_t; + +/* This function initializes a new linked list. */ +linked_list_t* initialize_linked_list(); +/* This function appends a node to the given linked list. */ +int append_node(linked_list_t *list, double_node_t *node); +/* This function prepends a node the the given linked list. */ +int prepend_node(linked_list_t *list, double_node_t *node); +/* This function creates and appends a node to the given linked list. */ +int append_node_data(linked_list_t *list, void *data); +/* This function inserts a node at the ith place. */ +int add_node_i(linked_list_t *list, node_t *node, int i); +/* This function creates and inserts a node at the ith place. */ +int add_node_data_i(linked_list_t *list, void *data, int i); +/* This function reads the data at the ith node. */ +void* read_node_i(linked_list_t *list, int i); +/* This function retrieves a pointer to the ith node. */ +node_t* get_node_i(linked_list_t *list, int i); +/* This function attempts to find the index of a given node, by pointer. */ +int get_node_index_pointer(linked_list_t *list, node_t *node); +/* This function attempts to find the index of a given node, by data. - TODO: implement! */ +/* This function deletes the ith node. */ +int remove_node_i(linked_list_t *list, int i); +/* This function deletes the ith node and the data stored within. */ +int remove_node_i_data(linked_list_t *list, int i, void (*free_function)()); +/* This function reads the data at the first node. */ +void* read_node_head(linked_list_t *list); +/* This function retrieves the first node. */ +node_t* get_node_head(linked_list_t *list); +/* This function deletes the first node. */ +int remove_node_head(linked_list_t *list); +/* This function deletes the first node and the data thereof. */ +int remove_node_head_data(linked_list_t *list, void (*free_function)()); +/* This function reads the data at the last node. */ +void* read_node_tail(linked_list_t *list); +/* This function retrieves the last node. */ +node_t* get_node_tail(linked_list_t *list); +/* This function deletes the last node. */ +int remove_node_tail(linked_list_t *list); +/* This function deletes the last node and the data thereof. */ +int remove_node_tail_data(linked_list_t *list, void (*free_function)()); +/* This function deletes all the nodes of the given list and the list itself. */ +int clear_list(linked_list_t **list); +/* This function deletes all the nodes and data stored within of the given list and the list itself. */ +int clear_list_data(linked_list_t **list, void (*free_function)()); + +#endif /* SINGLE_LINKED_LIST_H */ diff --git a/linked_lists/double_linked_list.h~ b/linked_lists/double_linked_list.h~ new file mode 100644 index 0000000..0aaa7e5 --- /dev/null +++ b/linked_lists/double_linked_list.h~ @@ -0,0 +1,66 @@ +/* This header defines a single-linked-list and related functions. */ +/* Use the single nodes. */ +#include +#ifndef SINGLE_LINKED_LIST_H +#define SINGLE_LINKED_LIST_H +#include "../nodes/single_node.h" + +/* Constants. */ +#define SUCCESS_CODE_SIGNLE_LINKED_LIST_C 1 +#define FAILURE_CODE_SIGNLE_LINKED_LIST_C 0 +#define INDEX_NOT_FOUND_CODE_LINKED_LIST_C -1 +#define INVALID_INPUT_CODE_LINKED_LIST_C -2 +#define CODE_FREE_SUCCESS_MALFORMED_LINKED_LIST_C -1 +#define INDEX_HEAD_LINKED_LIST_C 0 + +/* The actual linked list struct. */ +typedef struct linked_list { + /* Stores the list's length. */ + int length; + /* Stores the head node pointer. */ + node_t *head; +} linked_list_t; + +/* This function initializes a new linked list. */ +linked_list_t* initialize_linked_list(); +/* This function appends a node to the given linked list. */ +int append_node(linked_list_t *list, node_t *node); +/* This function creates and appends a node to the given linked list. */ +int append_node_data(linked_list_t *list, void *data); +/* This function inserts a node at the ith place. */ +int add_node_i(linked_list_t *list, node_t *node, int i); +/* This function creates and inserts a node at the ith place. */ +int add_node_data_i(linked_list_t *list, void *data, int i); +/* This function reads the data at the ith node. */ +void* read_node_i(linked_list_t *list, int i); +/* This function retrieves a pointer to the ith node. */ +node_t* get_node_i(linked_list_t *list, int i); +/* This function attempts to find the index of a given node, by pointer. */ +int get_node_index_pointer(linked_list_t *list, node_t *node); +/* This function attempts to find the index of a given node, by data. - TODO: implement! */ +/* This function deletes the ith node. */ +int remove_node_i(linked_list_t *list, int i); +/* This function deletes the ith node and the data stored within. */ +int remove_node_i_data(linked_list_t *list, int i, void (*free_function)()); +/* This function reads the data at the first node. */ +void* read_node_head(linked_list_t *list); +/* This function retrieves the first node. */ +node_t* get_node_head(linked_list_t *list); +/* This function deletes the first node. */ +int remove_node_head(linked_list_t *list); +/* This function deletes the first node and the data thereof. */ +int remove_node_head_data(linked_list_t *list, void (*free_function)()); +/* This function reads the data at the last node. */ +void* read_node_tail(linked_list_t *list); +/* This function retrieves the last node. */ +node_t* get_node_tail(linked_list_t *list); +/* This function deletes the last node. */ +int remove_node_tail(linked_list_t *list); +/* This function deletes the last node and the data thereof. */ +int remove_node_tail_data(linked_list_t *list, void (*free_function)()); +/* This function deletes all the nodes of the given list and the list itself. */ +int clear_list(linked_list_t **list); +/* This function deletes all the nodes and data stored within of the given list and the list itself. */ +int clear_list_data(linked_list_t **list, void (*free_function)()); + +#endif /* SINGLE_LINKED_LIST_H */ diff --git a/linked_lists/single_linked_list.c b/linked_lists/single_linked_list.c new file mode 100644 index 0000000..55110c3 --- /dev/null +++ b/linked_lists/single_linked_list.c @@ -0,0 +1,372 @@ +/* This file contains the function implementations for single linked lists. */ +/* Include guard + includes. */ +#ifndef SINGLE_LINKED_LIST_C +#define SINGLE_LINKED_LIST_C +#include "single_linked_list.h" +#endif /* SINGLE_LINKED_LIST_C */ + +/* This function initializes a new linked list, returns NULL on failure. */ +linked_list_t* initialize_linked_list() { + /* Variables. */ + linked_list_t *result; + + /* Attempt to allocate. */ + result = (linked_list_t*) malloc(sizeof(linked_list_t)); + + /* Check if the allocation worked. */ + if (result == NULL) + return NULL; + + /* Initialize the internal fields. */ + result->length = 0; + result->head = NULL; + + /* Return the result. */ + return result; +} + +/* This function appends a node to the given linked list, returns 1 on success and 0 on failure. */ +int append_node(linked_list_t *list, node_t *node) { + /* Input sanity check. */ + if (list == NULL || node == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Check if we can append at the start. */ + if (list->head == NULL) { + list->head = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + } + /* Loop till we get to the end. */ + node_t *current = list->head; + while (current->next != NULL) { + current = current->next; + } + /* Got to the end, append and add. */ + current->next = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; +} + +/* This function prepends a node to the given linked list, returns 1 on success and 0 on failure. */ +int prepend_node(linked_list_t *list, node_t *node) { + /* Input sanity check. */ + if (list == NULL || node == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Check if we can prepend at the start. */ + if (list->head == NULL) { + list->head = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + } + /* Set the node's next to the current head, and swap. */ + node->next = list->head; + list->head = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; +} + +/* This function creates and appends a node to the given linked list, returns 1 on success and 0 on failure. */ +int append_node_data(linked_list_t *list, void *data) { + /* Input sanity check. */ + if (list == NULL || data == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Attempt to create a node. */ + node_t *node = (node_t*) malloc(sizeof(node_t)); + if (node == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Insert the data. */ + node->data = data; + /* Delegate the work. */ + return append_node(list, node); +} + +/* This function creates and prepends a node to the given linked list, returns 1 on success and 0 on failure. */ +int prepend_node_data(linked_list_t *list, void *data) { + /* Input sanity check. */ + if (list == NULL || data == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Attempt to create a node. */ + node_t *node = (node_t*) malloc(sizeof(node_t)); + if (node == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Insert the data. */ + node->data = data; + /* Delegate the work. */ + return prepend_node(list, node); +} + +/* This function inserts a node at the ith place, returns 1 on success and 0 on failure. */ +int add_node_i(linked_list_t *list, node_t *node, int i) { + /* Input sanity check. */ + if (list == NULL || node == NULL || list->length <= i) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* TODO: Check that this function is correct. */ + /* Deal with special case of head. */ + if (i == 0) { + node->next = list->head; + list->head = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + } + /* Loop till we get to the right place. */ + node_t *current = list->head; + for (; i > 1; i--) + current = current->next; + /* Insert the node. */ + node->next = current->next; + current->next = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; +} + +/* This function creates and inserts a node at the ith place, returns 1 in success and 0 on failure. */ +int add_node_data_i(linked_list_t *list, void *data, int i) { + /* Input sanity check. */ + if (list == NULL || list->length <= i) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Attempt to create a node. */ + node_t *node = (node_t*) malloc(sizeof(node_t)); + if (node == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Insert the data. */ + node->data = data; + /* Delegate. */ + return add_node_i(list, node, i); +} + +/* This function reads the data at the ith node, returns NULL on failure or NULL data! */ +void* read_node_i(linked_list_t *list, int i) { + /* Input sanity check. */ + if (list == NULL || list->length <= i) + return NULL; + /* Loop and read. */ + node_t *current = list->head; + for (; i > 0; i--) + current = current->next; + /* Got to the requested node, return the stored data. */ + return current->data; +} + +/* This function retrieves a pointer to the ith node, returns NULL on failure. */ +node_t* get_node_i(linked_list_t *list, int i) { + /* Input sanity check */ + if (list == NULL || list->length <= i) + return NULL; + /* Loop. */ + node_t *current = list->head; + for (; i > 0; i--) + current = current->next; + /* Got to the requested node, return the pointer. */ + return current; +} + +/* This function attempts to find the index of a given node, by pointer. */ +/* Returns -2 on invalid input, and -1 when no found. */ +int get_node_index_pointer(linked_list_t *list, node_t *node){ + /* Sanity check. */ + if (list == NULL || node == NULL) + return INVALID_INPUT_CODE_LINKED_LIST_C; + /* Local variables. */ + node_t *current; + int i = 0; + /* Attempt to search. */ + if (list->head == NULL) + return INDEX_NOT_FOUND_CODE_LINKED_LIST_C; + current = list->head; + while (current != node) { + current = current->next; + i++; + } + /* Check if we found it or not. */ + return (i >= list->length) ? INDEX_NOT_FOUND_CODE_LINKED_LIST_C : i; +} + +/* This function deletes the ith node, returns 1 on success and 0 on failure. */ +int remove_node_i(linked_list_t *list, int i) { + /* Input sanity check */ + if (list == NULL || list->length <= i) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Deal with the special case of the head node. */ + if (i == 0) { + if (list->head == NULL) + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + node_t *tmp = list->head; + list->head = tmp->next; + tmp->next = NULL; + free(tmp); + (list->length)--; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + } + /* Loop. */ + node_t *current = list->head; + for (; i > 1; i--) + current = current->next; + /* Got to the requested node, delete it. */ + node_t *tmp = current->next; + current->next = tmp->next; + tmp->next = NULL; + free(tmp); + (list->length)--; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; +} + +/* This function deletes the ith node with the data stored within it, returns 1 on success and 0 on failure. */ +/* A free function pointer of NULL value causes the use of the internal stdlib free(). */ +int remove_node_i_data(linked_list_t *list, int i, void (*free_function)()) { + /* Input sanity check */ + if (list == NULL || list->length <= i) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Deal with the special case of the head node. */ + if (i == 0) { + if (list->head == NULL) + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + node_t *tmp = list->head; + list->head = tmp->next; + tmp->next = NULL; + if (free_function == NULL) + free(tmp->data); + else + free_function(tmp->data); + free(tmp); + (list->length)--; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + } + /* Loop. */ + node_t *current = list->head; + for (; i > 1; i--) + current = current->next; + /* Got to the requested node, delete it. */ + node_t *tmp = current->next; + current->next = tmp->next; + tmp->next = NULL; + if (free_function == NULL) + free(tmp->data); + else + free_function(tmp->data); + free(tmp); + (list->length)--; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; +} + +/* This function reads the data at the first node, note that it will return NULL on invalid input or first node being NULL. */ +void* read_node_head(linked_list_t *list) { + /* Delegate. */ + return read_node_i(list, INDEX_HEAD_LINKED_LIST_C); +} + +/* This function retrieves the first node, note that it will return NULL on invalid input or first node being NULL. */ +node_t* get_node_head(linked_list_t *list) { + /* Delegate. */ + return get_node_i(list, INDEX_HEAD_LINKED_LIST_C); +} + +/* This function deletes the first node, returns 1 on success and 0 on failure. */ +int remove_node_head(linked_list_t *list) { + /* Delegate. */ + return remove_node_i(list, INDEX_HEAD_LINKED_LIST_C); +} + +/* This function deletes the first node and the contents thereof, returns 1 on success and 0 on failure. */ +/* If the free_function is NULL, will use stdlib's free() instead. */ +int remove_node_head_data(linked_list_t *list, void (*free_function)()) { + /* Delegate. */ + return remove_node_i_data(list, INDEX_HEAD_LINKED_LIST_C, free_function); +} + +/* This function reads the data at the last node, will return NULL on invalid input or first node being NULL. */ +void* read_node_tail(linked_list_t *list) { + /* Sanity check. */ + if (list == NULL || list->head == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Delegate. */ + return read_node_i(list, list->length - 1); +} + +/* This function retrieves the last node, will return NULL on invalid input or the first node being NULL. */ +node_t* get_node_tail(linked_list_t *list) { + /* Sanity check. */ + if (list == NULL || list->head == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Delegate. */ + return get_node_i(list, list->length - 1); +} + +/* This function deletes the last node, returns 1 on success and 0 on failure. */ +int remove_node_tail(linked_list_t *list) { + /* Sanity check. */ + if (list == NULL || list->head == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Delegate. */ + return remove_node_i(list, list->length - 1); +} + +/* This function deletes the last node and the data thereof, returns 1 on success and 0 on failure. */ +/* If the free_function is NULL, will use stdlib's free() instead. */ +int remove_node_tail_data(linked_list_t *list, void (*free_function)()) { + /* Sanity check. */ + if (list == NULL || list->head == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Delegate. */ + return remove_node_i_data(list, list->length - 1, free_function); +} + +/* This function deletes all the nodes of the given list and the list itself. */ +/* Note that it doesn't touch the data, returns 1 on success and 0 on failure - failure is potentially undefined behavior! */ +/* Will return -1 when the list was freed successfully but it was initially malformed. */ +int clear_list(linked_list_t **list) { + /* Sanity check. */ + if (list == NULL || *list == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Local variables. */ + node_t *current = (*list)->head; + node_t *tmp; + int length; + int count = 0; + /* Loop and free. */ + while(current != NULL) { + count++; + tmp = current->next; + free(current); + current = tmp; + } + /* Save the list's length. */ + length = (*list)->length; + + /* Should all be freed by now, free the list and return. */ + free(*list); + *list = NULL; + return (count == length) ? SUCCESS_CODE_SIGNLE_LINKED_LIST_C : CODE_FREE_SUCCESS_MALFORMED_LINKED_LIST_C; +} + +/* This function deletes all the nodes and data stored within of the given list and the list itself. */ +/* Returns 1 on success and 0 on failure, undefined behavior in the latter. Will return -1 when the list was freed successfully but was initially malformed. */ +/* If free_function is NULL will use STDLIB free instead. */ +int clear_list_data(linked_list_t **list, void (*free_function)()) { + /* Sanity check. */ + if (list == NULL || *list == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Local variables. */ + node_t *current = (*list)->head; + node_t *tmp; + int length; + int count = 0; + /* Loop and free. */ + while(current != NULL) { + count++; + tmp = current->next; + if (free_function != NULL) { + free_function(current->data); + } else { + free(current->data); + } + free(current); + current = tmp; + } + /* Save the list's length. */ + length = (*list)->length; + + /* Should all be freed by now, free the list and return. */ + free(*list); + *list = NULL; + return (count == length) ? SUCCESS_CODE_SIGNLE_LINKED_LIST_C : CODE_FREE_SUCCESS_MALFORMED_LINKED_LIST_C; +} diff --git a/linked_lists/single_linked_list.c~ b/linked_lists/single_linked_list.c~ new file mode 100644 index 0000000..dcad0e9 --- /dev/null +++ b/linked_lists/single_linked_list.c~ @@ -0,0 +1,357 @@ +/* This file contains the function implementations for single linked lists. */ +/* Include guard + includes. */ +#ifndef SINGLE_LINKED_LIST_C +#define SINGLE_LINKED_LIST_C +#include "single_linked_list.h" +#endif /* SINGLE_LINKED_LIST_C */ + +/* This function initializes a new linked list, returns NULL on failure. */ +linked_list_t* initialize_linked_list() { + /* Variables. */ + linked_list_t *result; + + /* Attempt to allocate. */ + result = (linked_list_t*) malloc(sizeof(linked_list_t)); + + /* Check if the allocation worked. */ + if (result == NULL) + return NULL; + + /* Initialize the internal fields. */ + result->length = 0; + result->head = NULL; + + /* Return the result. */ + return result; +} + +/* This function appends a node to the given linked list, returns 1 on success and 0 on failure. */ +int append_node(linked_list_t *list, node_t *node) { + /* Input sanity check. */ + if (list == NULL || node == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Check if we can append at the start. */ + if (list->head == NULL) { + list->head = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + } + /* Loop till we get to the end. */ + node_t *current = list->head; + while (current->next != NULL) { + current = current->next; + } + /* Got to the end, append and add. */ + current->next = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; +} + +/* This function prepends a node to the given linked list, returns 1 on success and 0 on failure. */ +int prepend_node(linked_list_t *list, node_t *node) { + /* Input sanity check. */ + if (list == NULL || node == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Check if we can prepend at the start. */ + if (list->head == NULL) { + list->head = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + } + /* Set the node's next to the current head, and swap. */ + node->next = list->head; + list->head = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; +} + +/* This function creates and appends a node to the given linked list, returns 1 on success and 0 on failure. */ +int append_node_data(linked_list_t *list, void *data) { + /* Input sanity check. */ + if (list == NULL || data == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Attempt to create a node. */ + node_t *node = (node_t*) malloc(sizeof(node_t)); + if (node == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Insert the data. */ + node->data = data; + /* Delegate the work. */ + return append_node(list, node); +} + +/* This function inserts a node at the ith place, returns 1 on success and 0 on failure. */ +int add_node_i(linked_list_t *list, node_t *node, int i) { + /* Input sanity check. */ + if (list == NULL || node == NULL || list->length <= i) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* TODO: Check that this function is correct. */ + /* Deal with special case of head. */ + if (i == 0) { + node->next = list->head; + list->head = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + } + /* Loop till we get to the right place. */ + node_t *current = list->head; + for (; i > 1; i--) + current = current->next; + /* Insert the node. */ + node->next = current->next; + current->next = node; + (list->length)++; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; +} + +/* This function creates and inserts a node at the ith place, returns 1 in success and 0 on failure. */ +int add_node_data_i(linked_list_t *list, void *data, int i) { + /* Input sanity check. */ + if (list == NULL || list->length <= i) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Attempt to create a node. */ + node_t *node = (node_t*) malloc(sizeof(node_t)); + if (node == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Insert the data. */ + node->data = data; + /* Delegate. */ + return add_node_i(list, node, i); +} + +/* This function reads the data at the ith node, returns NULL on failure or NULL data! */ +void* read_node_i(linked_list_t *list, int i) { + /* Input sanity check. */ + if (list == NULL || list->length <= i) + return NULL; + /* Loop and read. */ + node_t *current = list->head; + for (; i > 0; i--) + current = current->next; + /* Got to the requested node, return the stored data. */ + return current->data; +} + +/* This function retrieves a pointer to the ith node, returns NULL on failure. */ +node_t* get_node_i(linked_list_t *list, int i) { + /* Input sanity check */ + if (list == NULL || list->length <= i) + return NULL; + /* Loop. */ + node_t *current = list->head; + for (; i > 0; i--) + current = current->next; + /* Got to the requested node, return the pointer. */ + return current; +} + +/* This function attempts to find the index of a given node, by pointer. */ +/* Returns -2 on invalid input, and -1 when no found. */ +int get_node_index_pointer(linked_list_t *list, node_t *node){ + /* Sanity check. */ + if (list == NULL || node == NULL) + return INVALID_INPUT_CODE_LINKED_LIST_C; + /* Local variables. */ + node_t *current; + int i = 0; + /* Attempt to search. */ + if (list->head == NULL) + return INDEX_NOT_FOUND_CODE_LINKED_LIST_C; + current = list->head; + while (current != node) { + current = current->next; + i++; + } + /* Check if we found it or not. */ + return (i >= list->length) ? INDEX_NOT_FOUND_CODE_LINKED_LIST_C : i; +} + +/* This function deletes the ith node, returns 1 on success and 0 on failure. */ +int remove_node_i(linked_list_t *list, int i) { + /* Input sanity check */ + if (list == NULL || list->length <= i) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Deal with the special case of the head node. */ + if (i == 0) { + if (list->head == NULL) + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + node_t *tmp = list->head; + list->head = tmp->next; + tmp->next = NULL; + free(tmp); + (list->length)--; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + } + /* Loop. */ + node_t *current = list->head; + for (; i > 1; i--) + current = current->next; + /* Got to the requested node, delete it. */ + node_t *tmp = current->next; + current->next = tmp->next; + tmp->next = NULL; + free(tmp); + (list->length)--; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; +} + +/* This function deletes the ith node with the data stored within it, returns 1 on success and 0 on failure. */ +/* A free function pointer of NULL value causes the use of the internal stdlib free(). */ +int remove_node_i_data(linked_list_t *list, int i, void (*free_function)()) { + /* Input sanity check */ + if (list == NULL || list->length <= i) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Deal with the special case of the head node. */ + if (i == 0) { + if (list->head == NULL) + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + node_t *tmp = list->head; + list->head = tmp->next; + tmp->next = NULL; + if (free_function == NULL) + free(tmp->data); + else + free_function(tmp->data); + free(tmp); + (list->length)--; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; + } + /* Loop. */ + node_t *current = list->head; + for (; i > 1; i--) + current = current->next; + /* Got to the requested node, delete it. */ + node_t *tmp = current->next; + current->next = tmp->next; + tmp->next = NULL; + if (free_function == NULL) + free(tmp->data); + else + free_function(tmp->data); + free(tmp); + (list->length)--; + return SUCCESS_CODE_SIGNLE_LINKED_LIST_C; +} + +/* This function reads the data at the first node, note that it will return NULL on invalid input or first node being NULL. */ +void* read_node_head(linked_list_t *list) { + /* Delegate. */ + return read_node_i(list, INDEX_HEAD_LINKED_LIST_C); +} + +/* This function retrieves the first node, note that it will return NULL on invalid input or first node being NULL. */ +node_t* get_node_head(linked_list_t *list) { + /* Delegate. */ + return get_node_i(list, INDEX_HEAD_LINKED_LIST_C); +} + +/* This function deletes the first node, returns 1 on success and 0 on failure. */ +int remove_node_head(linked_list_t *list) { + /* Delegate. */ + return remove_node_i(list, INDEX_HEAD_LINKED_LIST_C); +} + +/* This function deletes the first node and the contents thereof, returns 1 on success and 0 on failure. */ +/* If the free_function is NULL, will use stdlib's free() instead. */ +int remove_node_head_data(linked_list_t *list, void (*free_function)()) { + /* Delegate. */ + return remove_node_i_data(list, INDEX_HEAD_LINKED_LIST_C, free_function); +} + +/* This function reads the data at the last node, will return NULL on invalid input or first node being NULL. */ +void* read_node_tail(linked_list_t *list) { + /* Sanity check. */ + if (list == NULL || list->head == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Delegate. */ + return read_node_i(list, list->length - 1); +} + +/* This function retrieves the last node, will return NULL on invalid input or the first node being NULL. */ +node_t* get_node_tail(linked_list_t *list) { + /* Sanity check. */ + if (list == NULL || list->head == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Delegate. */ + return get_node_i(list, list->length - 1); +} + +/* This function deletes the last node, returns 1 on success and 0 on failure. */ +int remove_node_tail(linked_list_t *list) { + /* Sanity check. */ + if (list == NULL || list->head == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Delegate. */ + return remove_node_i(list, list->length - 1); +} + +/* This function deletes the last node and the data thereof, returns 1 on success and 0 on failure. */ +/* If the free_function is NULL, will use stdlib's free() instead. */ +int remove_node_tail_data(linked_list_t *list, void (*free_function)()) { + /* Sanity check. */ + if (list == NULL || list->head == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Delegate. */ + return remove_node_i_data(list, list->length - 1, free_function); +} + +/* This function deletes all the nodes of the given list and the list itself. */ +/* Note that it doesn't touch the data, returns 1 on success and 0 on failure - failure is potentially undefined behavior! */ +/* Will return -1 when the list was freed successfully but it was initially malformed. */ +int clear_list(linked_list_t **list) { + /* Sanity check. */ + if (list == NULL || *list == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Local variables. */ + node_t *current = (*list)->head; + node_t *tmp; + int length; + int count = 0; + /* Loop and free. */ + while(current != NULL) { + count++; + tmp = current->next; + free(current); + current = tmp; + } + /* Save the list's length. */ + length = (*list)->length; + + /* Should all be freed by now, free the list and return. */ + free(*list); + *list = NULL; + return (count == length) ? SUCCESS_CODE_SIGNLE_LINKED_LIST_C : CODE_FREE_SUCCESS_MALFORMED_LINKED_LIST_C; +} + +/* This function deletes all the nodes and data stored within of the given list and the list itself. */ +/* Returns 1 on success and 0 on failure, undefined behavior in the latter. Will return -1 when the list was freed successfully but was initially malformed. */ +/* If free_function is NULL will use STDLIB free instead. */ +int clear_list_data(linked_list_t **list, void (*free_function)()) { + /* Sanity check. */ + if (list == NULL || *list == NULL) + return FAILURE_CODE_SIGNLE_LINKED_LIST_C; + /* Local variables. */ + node_t *current = (*list)->head; + node_t *tmp; + int length; + int count = 0; + /* Loop and free. */ + while(current != NULL) { + count++; + tmp = current->next; + if (free_function != NULL) { + free_function(current->data); + } else { + free(current->data); + } + free(current); + current = tmp; + } + /* Save the list's length. */ + length = (*list)->length; + + /* Should all be freed by now, free the list and return. */ + free(*list); + *list = NULL; + return (count == length) ? SUCCESS_CODE_SIGNLE_LINKED_LIST_C : CODE_FREE_SUCCESS_MALFORMED_LINKED_LIST_C; +} diff --git a/linked_lists/single_linked_list.h b/linked_lists/single_linked_list.h new file mode 100644 index 0000000..e6dac9f --- /dev/null +++ b/linked_lists/single_linked_list.h @@ -0,0 +1,70 @@ +/* This header defines a single-linked-list and related functions. */ +/* Use the single nodes. */ +#include +#ifndef SINGLE_LINKED_LIST_H +#define SINGLE_LINKED_LIST_H +#include "../nodes/single_node.h" + +/* Constants. */ +#define SUCCESS_CODE_SIGNLE_LINKED_LIST_C 1 +#define FAILURE_CODE_SIGNLE_LINKED_LIST_C 0 +#define INDEX_NOT_FOUND_CODE_LINKED_LIST_C -1 +#define INVALID_INPUT_CODE_LINKED_LIST_C -2 +#define CODE_FREE_SUCCESS_MALFORMED_LINKED_LIST_C -1 +#define INDEX_HEAD_LINKED_LIST_C 0 + +/* The actual linked list struct. */ +typedef struct linked_list { + /* Stores the list's length. */ + int length; + /* Stores the head node pointer. */ + node_t *head; +} linked_list_t; + +/* This function initializes a new linked list. */ +linked_list_t* initialize_linked_list(); +/* This function appends a node to the given linked list. */ +int append_node(linked_list_t *list, node_t *node); +/* This function prepends a node to the given linked list. */ +int prepend_node(linked_list_t *list, node_t *node); +/* This function creates and appends a node to the given linked list. */ +int append_node_data(linked_list_t *list, void *data); +/* This function creates and prepends a node to the given linked list. */ +int prepend_node_data(linked_list_t *list, void *data); +/* This function inserts a node at the ith place. */ +int add_node_i(linked_list_t *list, node_t *node, int i); +/* This function creates and inserts a node at the ith place. */ +int add_node_data_i(linked_list_t *list, void *data, int i); +/* This function reads the data at the ith node. */ +void* read_node_i(linked_list_t *list, int i); +/* This function retrieves a pointer to the ith node. */ +node_t* get_node_i(linked_list_t *list, int i); +/* This function attempts to find the index of a given node, by pointer. */ +int get_node_index_pointer(linked_list_t *list, node_t *node); +/* This function attempts to find the index of a given node, by data. - TODO: implement! */ +/* This function deletes the ith node. */ +int remove_node_i(linked_list_t *list, int i); +/* This function deletes the ith node and the data stored within. */ +int remove_node_i_data(linked_list_t *list, int i, void (*free_function)()); +/* This function reads the data at the first node. */ +void* read_node_head(linked_list_t *list); +/* This function retrieves the first node. */ +node_t* get_node_head(linked_list_t *list); +/* This function deletes the first node. */ +int remove_node_head(linked_list_t *list); +/* This function deletes the first node and the data thereof. */ +int remove_node_head_data(linked_list_t *list, void (*free_function)()); +/* This function reads the data at the last node. */ +void* read_node_tail(linked_list_t *list); +/* This function retrieves the last node. */ +node_t* get_node_tail(linked_list_t *list); +/* This function deletes the last node. */ +int remove_node_tail(linked_list_t *list); +/* This function deletes the last node and the data thereof. */ +int remove_node_tail_data(linked_list_t *list, void (*free_function)()); +/* This function deletes all the nodes of the given list and the list itself. */ +int clear_list(linked_list_t **list); +/* This function deletes all the nodes and data stored within of the given list and the list itself. */ +int clear_list_data(linked_list_t **list, void (*free_function)()); + +#endif /* SINGLE_LINKED_LIST_H */ diff --git a/linked_lists/single_linked_list.h~ b/linked_lists/single_linked_list.h~ new file mode 100644 index 0000000..0aaa7e5 --- /dev/null +++ b/linked_lists/single_linked_list.h~ @@ -0,0 +1,66 @@ +/* This header defines a single-linked-list and related functions. */ +/* Use the single nodes. */ +#include +#ifndef SINGLE_LINKED_LIST_H +#define SINGLE_LINKED_LIST_H +#include "../nodes/single_node.h" + +/* Constants. */ +#define SUCCESS_CODE_SIGNLE_LINKED_LIST_C 1 +#define FAILURE_CODE_SIGNLE_LINKED_LIST_C 0 +#define INDEX_NOT_FOUND_CODE_LINKED_LIST_C -1 +#define INVALID_INPUT_CODE_LINKED_LIST_C -2 +#define CODE_FREE_SUCCESS_MALFORMED_LINKED_LIST_C -1 +#define INDEX_HEAD_LINKED_LIST_C 0 + +/* The actual linked list struct. */ +typedef struct linked_list { + /* Stores the list's length. */ + int length; + /* Stores the head node pointer. */ + node_t *head; +} linked_list_t; + +/* This function initializes a new linked list. */ +linked_list_t* initialize_linked_list(); +/* This function appends a node to the given linked list. */ +int append_node(linked_list_t *list, node_t *node); +/* This function creates and appends a node to the given linked list. */ +int append_node_data(linked_list_t *list, void *data); +/* This function inserts a node at the ith place. */ +int add_node_i(linked_list_t *list, node_t *node, int i); +/* This function creates and inserts a node at the ith place. */ +int add_node_data_i(linked_list_t *list, void *data, int i); +/* This function reads the data at the ith node. */ +void* read_node_i(linked_list_t *list, int i); +/* This function retrieves a pointer to the ith node. */ +node_t* get_node_i(linked_list_t *list, int i); +/* This function attempts to find the index of a given node, by pointer. */ +int get_node_index_pointer(linked_list_t *list, node_t *node); +/* This function attempts to find the index of a given node, by data. - TODO: implement! */ +/* This function deletes the ith node. */ +int remove_node_i(linked_list_t *list, int i); +/* This function deletes the ith node and the data stored within. */ +int remove_node_i_data(linked_list_t *list, int i, void (*free_function)()); +/* This function reads the data at the first node. */ +void* read_node_head(linked_list_t *list); +/* This function retrieves the first node. */ +node_t* get_node_head(linked_list_t *list); +/* This function deletes the first node. */ +int remove_node_head(linked_list_t *list); +/* This function deletes the first node and the data thereof. */ +int remove_node_head_data(linked_list_t *list, void (*free_function)()); +/* This function reads the data at the last node. */ +void* read_node_tail(linked_list_t *list); +/* This function retrieves the last node. */ +node_t* get_node_tail(linked_list_t *list); +/* This function deletes the last node. */ +int remove_node_tail(linked_list_t *list); +/* This function deletes the last node and the data thereof. */ +int remove_node_tail_data(linked_list_t *list, void (*free_function)()); +/* This function deletes all the nodes of the given list and the list itself. */ +int clear_list(linked_list_t **list); +/* This function deletes all the nodes and data stored within of the given list and the list itself. */ +int clear_list_data(linked_list_t **list, void (*free_function)()); + +#endif /* SINGLE_LINKED_LIST_H */ diff --git a/nodes/double_node.h b/nodes/double_node.h new file mode 100644 index 0000000..ef7b96b --- /dev/null +++ b/nodes/double_node.h @@ -0,0 +1,12 @@ +/* This header defines a double node, for two-way linking. */ +#ifndef DOUBLE_NODE_H +#define DOUBLE_NODE_H +typedef struct double_node { + /* Previous node. */ + struct double_node *previous; + /* Next node. */ + struct double_node *next; + /* Data. */ + void *data; +} double_node_t; +#endif DOUBLE_NODE_H diff --git a/nodes/double_node.h~ b/nodes/double_node.h~ new file mode 100644 index 0000000..ffff343 --- /dev/null +++ b/nodes/double_node.h~ @@ -0,0 +1,12 @@ +/* This header defines a double node, for two-way linking. */ +#ifndef DOUBLE_NODE_H +#define DOUBLE_NODE_H +typedef struct node { + /* Previous node. */ + struct node *previous; + /* Next node. */ + struct node *next; + /* Data. */ + void *data; +} node_t; +#endif DOUBLE_NODE_H diff --git a/nodes/single_node.h b/nodes/single_node.h new file mode 100644 index 0000000..da20460 --- /dev/null +++ b/nodes/single_node.h @@ -0,0 +1,10 @@ +/* This header defines a single node, for one-way linking. */ +#ifndef SINGLE_NODE_H +#define SINGLE_NODE_H +typedef struct node { + /* Next node. */ + struct node *next; + /* Data. */ + void *data; +} node_t; +#endif /* SINGLE_NODE_H */ diff --git a/nodes/single_node.h~ b/nodes/single_node.h~ new file mode 100644 index 0000000..3f150e8 --- /dev/null +++ b/nodes/single_node.h~ @@ -0,0 +1,7 @@ +/* This header defines a single node, for one-way linking. */ +typedef struct node { + /* Next node. */ + struct node *next; + /* Data. */ + void *data; +} node_t; diff --git a/nodes/tree_node.h b/nodes/tree_node.h new file mode 100644 index 0000000..042614b --- /dev/null +++ b/nodes/tree_node.h @@ -0,0 +1,12 @@ +/* This header defines a node in a binary tree. */ +#ifndef TREE_NODE_H +#define TREE_NODE_H +typedef struct tree_node { + /* Right node. */ + struct tree_node *right; + /* Left node. */ + struct tree_node *left; + /* Data. */ + void *data; +} tree_node_t; +#endif /* TREE_NODE_H */ diff --git a/nodes/tree_node.h~ b/nodes/tree_node.h~ new file mode 100644 index 0000000..49dba62 --- /dev/null +++ b/nodes/tree_node.h~ @@ -0,0 +1,12 @@ +/* This header defines a node in a binary tree. */ +#ifndef TREE_NODE_H +#define TREE_NODE_H +typedef struct tree_node { + /* Right node. */ + struct tree_node *right; + /* Left node. */ + struct tree_node *left; + /* Data. */ + void *data; +} tree_node_t; +#endif TREE_NODE_H diff --git a/stack/stack.c b/stack/stack.c new file mode 100644 index 0000000..0cd04e7 --- /dev/null +++ b/stack/stack.c @@ -0,0 +1,130 @@ +/* This file contains the function implementations for a stack. */ +/* Include guards + includes. */ +#ifndef STACK_C +#define STACK_C +/* Include statements. */ +#include "stack.h" +#endif /* STACK_C */ + +/* This function initializes a new empty stack. */ +/* Returns a valid pointer on success, and NULL on failure. */ +stack_t* initialize_stack() { + /* Variables. */ + stack_t *result; + + /* Attempt to allocate. */ + result = (stack_t*) malloc(sizeof(stack_t)); + if (result == NULL) + return NULL; + /* Allocation succeeded, initialize and return. */ + result->size = INITIAL_STACK_SIZE; + result->head = NULL; + return result; +} + +/* This function pops the current head node out, if it exists, otherwise will return NULL (also returns NULL on errornous input). */ +node_t* pop(stack_t *stack) { + /* Sanity check. */ + if (stack == NULL || stack->head == NULL) + return NULL; + + /* Remove the head. */ + node_t *head = stack->head; + stack->head = head->next; + (stack->size) -= 1; + + /* Return the head.*/ + return head; +} + +/* This function "peeks" at the top of the stack, will return NULL on error (in input/internal). */ +const void* peek(stack_t *stack) { + /* Sanity check. */ + if (stack == NULL) + return NULL; + +} + +/* This function pushes a node in, returns PUSH_SUCCESS on succes and PUSH_FAIL on failure. */ +/* Will fail for a NULL stack or node! */ +int push(stack_t *stack, node_t *node) { + /* Sanity check. */ + if (stack == NULL || node == NULL) + return PUSH_FAIL; + /* Try to push. */ + /* Increase the count. */ + (stack->size) += 1; + /* Check if the head is NULL or not. */ + if (stack->head == NULL) { + stack->head = node; + node->next = NULL; + return PUSH_SUCCESS; + } + /* Relink the head. */ + node->next = stack->head; + stack->head = node; + return PUSH_SUCCESS; +} + +/* This function creates a node, stores the given data and pushes it into the stack, will fail on a NULL stack or allocation errors. */ +/* Returns PUSH_SUCCESS on success, and PUSH_FAIL on failure. */ +int push_data(stack_t *stack, void *data) { + /* Sanity check. */ + if (stack == NULL) + return PUSH_FAIL; + /* Try to allocate the new node. */ + node_t *node = (node_t*) malloc(sizeof(node_t)); + if (node == NULL) + return PUSH_FAIL; + /* Store the data in the node. */ + node->data = data; + /* Delegate. */ + return push(stack, node); +} + +/* This function returns the stack's size, will return INVALID_SIZE for a NULL stack. */ +int stack_size(stack_t *stack) { + return (stack == NULL) ? INVALID_SIZE : stack->size; +} + +/* This function frees a stack, doesn't touch the data. */ +/* Takes a pointer to a pointer so it can set the original pointer to NULL. */ +void free_stack(stack_t **stack) { + /* Sanity check. */ + if (stack == NULL || *stack == NULL) + return; + /* Start by freeing node after node. */ + node_t *current = (*stack)->head; + node_t *tmp; + while (current != NULL) { + tmp = current->next; + free(current); + current = tmp; + } + /* Free the stack. */ + free(*stack); + *stack = NULL; +} + +/* This function frees a stack and the data stored within the nodes thereof, if free_function is NULL will use STDLIB's free() instead to free the data. */ +/* Takes a pointer to a pointer so it can set the original pointer to NULL. */ +void free_stack_data(stack_t **stack, void (*free_function)()) { + /* Sanity check. */ + if (stack == NULL || *stack == NULL) + return; + /* Start by freeing node after node. */ + node_t *current = (*stack)->head; + node_t *tmp; + while (current != NULL) { + tmp = current->next; + if (free_function != NULL) + free_function(current->data); + else + free(current->data); + free(current); + current = tmp; + } + /* Free the stack. */ + free(*stack); + *stack = NULL; +} diff --git a/stack/stack.c~ b/stack/stack.c~ new file mode 100644 index 0000000..0cd04e7 --- /dev/null +++ b/stack/stack.c~ @@ -0,0 +1,130 @@ +/* This file contains the function implementations for a stack. */ +/* Include guards + includes. */ +#ifndef STACK_C +#define STACK_C +/* Include statements. */ +#include "stack.h" +#endif /* STACK_C */ + +/* This function initializes a new empty stack. */ +/* Returns a valid pointer on success, and NULL on failure. */ +stack_t* initialize_stack() { + /* Variables. */ + stack_t *result; + + /* Attempt to allocate. */ + result = (stack_t*) malloc(sizeof(stack_t)); + if (result == NULL) + return NULL; + /* Allocation succeeded, initialize and return. */ + result->size = INITIAL_STACK_SIZE; + result->head = NULL; + return result; +} + +/* This function pops the current head node out, if it exists, otherwise will return NULL (also returns NULL on errornous input). */ +node_t* pop(stack_t *stack) { + /* Sanity check. */ + if (stack == NULL || stack->head == NULL) + return NULL; + + /* Remove the head. */ + node_t *head = stack->head; + stack->head = head->next; + (stack->size) -= 1; + + /* Return the head.*/ + return head; +} + +/* This function "peeks" at the top of the stack, will return NULL on error (in input/internal). */ +const void* peek(stack_t *stack) { + /* Sanity check. */ + if (stack == NULL) + return NULL; + +} + +/* This function pushes a node in, returns PUSH_SUCCESS on succes and PUSH_FAIL on failure. */ +/* Will fail for a NULL stack or node! */ +int push(stack_t *stack, node_t *node) { + /* Sanity check. */ + if (stack == NULL || node == NULL) + return PUSH_FAIL; + /* Try to push. */ + /* Increase the count. */ + (stack->size) += 1; + /* Check if the head is NULL or not. */ + if (stack->head == NULL) { + stack->head = node; + node->next = NULL; + return PUSH_SUCCESS; + } + /* Relink the head. */ + node->next = stack->head; + stack->head = node; + return PUSH_SUCCESS; +} + +/* This function creates a node, stores the given data and pushes it into the stack, will fail on a NULL stack or allocation errors. */ +/* Returns PUSH_SUCCESS on success, and PUSH_FAIL on failure. */ +int push_data(stack_t *stack, void *data) { + /* Sanity check. */ + if (stack == NULL) + return PUSH_FAIL; + /* Try to allocate the new node. */ + node_t *node = (node_t*) malloc(sizeof(node_t)); + if (node == NULL) + return PUSH_FAIL; + /* Store the data in the node. */ + node->data = data; + /* Delegate. */ + return push(stack, node); +} + +/* This function returns the stack's size, will return INVALID_SIZE for a NULL stack. */ +int stack_size(stack_t *stack) { + return (stack == NULL) ? INVALID_SIZE : stack->size; +} + +/* This function frees a stack, doesn't touch the data. */ +/* Takes a pointer to a pointer so it can set the original pointer to NULL. */ +void free_stack(stack_t **stack) { + /* Sanity check. */ + if (stack == NULL || *stack == NULL) + return; + /* Start by freeing node after node. */ + node_t *current = (*stack)->head; + node_t *tmp; + while (current != NULL) { + tmp = current->next; + free(current); + current = tmp; + } + /* Free the stack. */ + free(*stack); + *stack = NULL; +} + +/* This function frees a stack and the data stored within the nodes thereof, if free_function is NULL will use STDLIB's free() instead to free the data. */ +/* Takes a pointer to a pointer so it can set the original pointer to NULL. */ +void free_stack_data(stack_t **stack, void (*free_function)()) { + /* Sanity check. */ + if (stack == NULL || *stack == NULL) + return; + /* Start by freeing node after node. */ + node_t *current = (*stack)->head; + node_t *tmp; + while (current != NULL) { + tmp = current->next; + if (free_function != NULL) + free_function(current->data); + else + free(current->data); + free(current); + current = tmp; + } + /* Free the stack. */ + free(*stack); + *stack = NULL; +} diff --git a/stack/stack.h b/stack/stack.h new file mode 100644 index 0000000..be2465d --- /dev/null +++ b/stack/stack.h @@ -0,0 +1,41 @@ +/* This header file defines a stack (FIFO) structure and the associated function declarations. */ +#ifndef STACK_H +#define STACK_H +/* Include stdlib. */ +#include +/* Include the single node header. */ +#include "../nodes/single_node.h" + +/* Constants. */ +#define INITIAL_STACK_SIZE 0 +#define PUSH_SUCCESS 1 +#define PUSH_FAIL 0 +#define INVALID_SIZE -1 + +/* The actual stack struct. */ +typedef struct stack { + /* Store the stack's total size. */ + int size; + /* Stores the current last node. */ + node_t *head; +} stack_t; + +/* Function declarations. */ +/* This function initializes a new empty stack. */ +stack_t* initialize_stack(); +/* This function pops a node out. */ +node_t* pop(stack_t *stack); +/* This function "peeks" into the top node. */ +const void* peek(stack_t *stack); +/* This function pushes a node in. */ +int push(stack_t *stack, node_t *node); +/* This function creates a node, stores the data and pushes it in. */ +int push_data(stack_t *stack, void *data); +/* This function returns the stack's size. */ +int stack_size(stack_t *stack); +/* This function frees a stack, doen't touch the data. */ +void free_stack(stack_t **stack); +/* This function frees a stack and the data stored within. */ +void free_stack_data(stack_t **stack, void (*free_function)()); + +#endif /*STACK_H*/ diff --git a/stack/stack.h~ b/stack/stack.h~ new file mode 100644 index 0000000..e981115 --- /dev/null +++ b/stack/stack.h~ @@ -0,0 +1,41 @@ +/* This header file defines a stack (FIFO) structure and the associated function declarations. */ +#ifndef STACK_H +#define STACK_H +/* Include stdlib. */ +#include +/* Include the single node header. */ +#include "../nodes/single_node.h" + +/* Constants. */ +#define INITIAL_STACK_SIZE 0 +#define PUSH_SUCCESS 1 +#define PUSH_FAIL 0 +#define INVALID_SIZE -1 + +/* The actual stack struct. */ +typedef struct stack { + /* Store the stack's total size. */ + int size; + /* Stores the current last node. */ + node_t *head; +} stack_t; + +/* Function declarations. */ +/* This function initializes a new empty stack. */ +stack_t* initialize_stack(); +/* This function pops a node out. */ +node_t* pop(stack_t *stack); +/* This function "peeks" into the top node. */ +void* peek(stack_t *stack); +/* This function pushes a node in. */ +int push(stack_t *stack, node_t *node); +/* This function creates a node, stores the data and pushes it in. */ +int push_data(stack_t *stack, void *data); +/* This function returns the stack's size. */ +int stack_size(stack_t *stack); +/* This function frees a stack, doen't touch the data. */ +void free_stack(stack_t **stack); +/* This function frees a stack and the data stored within. */ +void free_stack_data(stack_t **stack, void (*free_function)()); + +#endif /*STACK_H*/ diff --git a/strings/strzcpy.c b/strings/strzcpy.c new file mode 100644 index 0000000..192bae6 --- /dev/null +++ b/strings/strzcpy.c @@ -0,0 +1,21 @@ +/* This file contains the function implementation for safe string copy. */ +/* Include guards + includes. */ +#ifndef STRZCPY_C +#define STRZCPY_C +/* Include statements. */ +#include "strzcpy.h" + +/** +* This function takes a destination buffer, a source buffer and a length. +* Copies the source into the destination, stopping when length is reached or end of destination (whichever is shorter). +* The copied string is always null-terminated when possible (might cause truncation). +* Will return the length copied (and if it overflowed). +*/ +char *strzcpy(char *restrict dst, const char* restrict src, size_t len) { + char *end = memccpy(dst, src, '\0', len); + if (!end) + dst[len - 1] = '\0'; + return end; +} + +#endif //STRZCPY_C diff --git a/strings/strzcpy.c~ b/strings/strzcpy.c~ new file mode 100644 index 0000000..98f1046 --- /dev/null +++ b/strings/strzcpy.c~ @@ -0,0 +1,18 @@ +/* This file contains the function implementation for safe string copy. */ +/* Include guards + includes. */ +#ifndef STRZCPY_C +#define STRZCPY_C +/* Include statements. */ +#include "strzcpy.h" + +/** +* This function takes a destination buffer, a source buffer and a length. +* Copies the source into the destination, stopping when length is reached or end of destination (whichever is shorter). +* The copied string is always null-terminated when possible (might cause truncation). +* Will return the length copied (and if it overflowed). +*/ +char *strzcpy(char *restrict dst, const char* restrict src, size_t len) { + +} + +#endif //STRZCPY_C diff --git a/strings/strzcpy.h b/strings/strzcpy.h new file mode 100644 index 0000000..dcb2a00 --- /dev/null +++ b/strings/strzcpy.h @@ -0,0 +1,16 @@ +/* This header file defines a strzcpy function, for general string copying (that is safer). */ +/* Include guards + includes. */ +#ifndef STRZCPY_H +#define STRZCPY_H +/* Include string.h */ +#include + + +/** +* This function takes a destination buffer, a source buffer and a length. +* Copies the source into the destination, stopping when length is reached or end of destination (whichever is shorter). +* The copied string is always null-terminated when possible (might cause truncation). +* Will return the length copied (and if it overflowed). +*/ +char *strzcpy(char *restrict dst, const char *restrict src, size_t len); +#endif //STRZCPY_H diff --git a/strings/strzcpy.h~ b/strings/strzcpy.h~ new file mode 100644 index 0000000..aef3942 --- /dev/null +++ b/strings/strzcpy.h~ @@ -0,0 +1,15 @@ +/* This header file defines a strzcpy function, for general string copying (that is safer). */ +#ifndef STRZCPY_H +#define STRZCPY_H +/* Include string.h */ +#include + + +/** +* This function takes a destination buffer, a source buffer and a length. +* Copies the source into the destination, stopping when length is reached or end of destination (whichever is shorter). +* The copied string is always null-terminated when possible (might cause truncation). +* Will return the length copied (and if it overflowed). +*/ +char *strzcpy(char *restrict dst, const char *restrict src, size_t len); +#endif //STRZCPY_H diff --git a/tests/a.out b/tests/a.out new file mode 100755 index 0000000..fa76651 Binary files /dev/null and b/tests/a.out differ diff --git a/tests/single_linked_list_tests.c b/tests/single_linked_list_tests.c new file mode 100644 index 0000000..a81464c --- /dev/null +++ b/tests/single_linked_list_tests.c @@ -0,0 +1,170 @@ +/* Include statements. */ +#include +#include +#include "../linked_lists/single_linked_list.c" + +/* Define constants. */ +#define PRINT_INFO_TESTING_START "Starting tests.\n" +#define PRINT_INFO_TESTING_END "Done testing.\n" +#define ERROR_TEXT_RANDOM_LIST_FAIL_ALLOCATION "Long list test failed because of allocation errors!\n" +#define SOME_TEST_FAILED "Recheck the tests, one of them failed!\n" +#define INITIAL_LIST_LENGTH 0 +#define LIST_LENGTH_ONE 1 +#define LIST_LENGTH_LONG_TEST 4096 + +/* Define functions. */ +node_t* generate_random_node(); +linked_list_t* generate_long_random_list(int length); +int list_count_length(linked_list_t *list); +int test_linked_lists(); + +/* Starting point. */ +int main() { + printf(PRINT_INFO_TESTING_START); + if (test_linked_lists()) { + printf(SOME_TEST_FAILED); + } + printf(PRINT_INFO_TESTING_END); +} + +/* This function generates a random number and puts it in a newly allocated node. */ +/* Caller has to free memory afterwards, returns NULL on failure. */ +node_t* generate_random_node() { + /* The node to return. */ + node_t* result; + int *value; + + /* Attempt to allocate the node. */ + result = (node_t*) malloc(sizeof(node_t)); + if (result == NULL) + return NULL; + value = (int*) malloc(sizeof(int)); + if (value == NULL) { + free(result); + return NULL; + } + *value = random(); + + /* Store and return. */ + result->next = NULL; + result->data = value; + return result; +} + +/* This function generates a long list with random values in the nodes, returns NULL on failures. */ +/* Length denotes the length of the list. */ +linked_list_t* generate_long_random_list(int length) { + /* Sanity check. */ + if (length <= 0) + return NULL; + /* Variables. */ + linked_list_t *list; + node_t *current; + int i; + + /* Allocate the list. */ + list = initialize_linked_list(); + if (list == NULL) + return NULL; + + /* Fill the list with random nodes. */ + /* First node. */ + current = generate_random_node(); + if (current == NULL) { + free(list); + return NULL; + } + /* Attempt to append. */ + if (!append_node(list, current)) { + free(current->data); + free(current); + free(list); + return NULL; + } + /* Loop and add the rest. */ + for (i = 1; i < length; i++) { + /* Generate and attempt to append. */ + current = generate_random_node(); + if (!append_node(list, current)) { + /* Abort. */ + free(current->data); + free(current); + clear_list_data(&list, NULL); + return NULL; + } + } + + /* Update the list's length. */ + list->length = length; + /* Return the result. */ + return list; +} + +/* This function checks the actual length of a list. */ +int list_count_length(linked_list_t *list) { + if (list == NULL || list->head == NULL) + return 0; + /* Loop and count. */ + node_t *current = list->head; + int count = 0; + while (current != NULL) { + count++; + current = current->next; + } + /* Return the result. */ + return count; +} + +/* This function does the testing. */ +int test_linked_lists() { + /* Local variables. */ + linked_list_t *list; + node_t *node, *tail; + + /* Initialize an empty list. */ + list = initialize_linked_list(); + /* Check that it was correctly created. */ + assert(list != NULL); + assert(list->length == INITIAL_LIST_LENGTH); + assert(list->head == NULL); + + /* Generate and store the node. */ + node = generate_random_node(); + + /* Attempt to add it to the list. */ + append_node(list, node); + /* Check that the list grew and the head got set. */ + assert(list->length == LIST_LENGTH_ONE); + assert(list->head != NULL && list->head == node); + assert(get_node_i(list, 0) == node); + assert(get_node_index_pointer(list, node) == 0); + + /* Attempt to free the nodes and then the list. */ + remove_node_i_data(list, 0, NULL); + assert(list->length == INITIAL_LIST_LENGTH); + assert(list->head == NULL); + node = NULL; + free(list); + list = NULL; + + /* Attempt to allocate a long list. */ + list = generate_long_random_list(LIST_LENGTH_LONG_TEST); + if (list == NULL) { + printf(ERROR_TEXT_RANDOM_LIST_FAIL_ALLOCATION); + return 1; + } + assert(list->length == LIST_LENGTH_LONG_TEST); + assert(list->length == list_count_length(list)); + /* Test the get head/tail functions. */ + assert(get_node_head(list) == list->head); + tail = get_node_tail(list); + assert(tail != NULL && tail->next == NULL); + /* Test the indexer functions. */ + assert(get_node_index_pointer(list, tail) == (list->length - 1)); + /* Test the freeing functions. */ + clear_list_data(&list, NULL); + assert(list == NULL); + + /* Ran successfully, return 0. */ + return 0; +} diff --git a/tests/single_linked_list_tests.c~ b/tests/single_linked_list_tests.c~ new file mode 100644 index 0000000..393e38b --- /dev/null +++ b/tests/single_linked_list_tests.c~ @@ -0,0 +1,170 @@ +/* Include statements. */ +#include +#include +#include "../linked_lists/single_linked_list.c" + +/* Define constants. */ +#define PRINT_INFO_TESTING_START "Starting tests.\n" +#define PRINT_INFO_TESTING_END "Done testing.\n" +#define ERROR_TEXT_RANDOM_LIST_FAIL_ALLOCATION "Long list test failed because of allocation errors!\n" +#define SOME_TEST_FAILED "Recheck the tests, one of them failed!\n" +#define INITIAL_LIST_LENGTH 0 +#define LIST_LENGTH_ONE 1 +#define LIST_LENGTH_LONG_TEST 131072 + +/* Define functions. */ +node_t* generate_random_node(); +linked_list_t* generate_long_random_list(int length); +int list_count_length(linked_list_t *list); +int test_linked_lists(); + +/* Starting point. */ +int main() { + printf(PRINT_INFO_TESTING_START); + if (test_linked_lists()) { + printf(SOME_TEST_FAILED); + } + printf(PRINT_INFO_TESTING_END); +} + +/* This function generates a random number and puts it in a newly allocated node. */ +/* Caller has to free memory afterwards, returns NULL on failure. */ +node_t* generate_random_node() { + /* The node to return. */ + node_t* result; + int *value; + + /* Attempt to allocate the node. */ + result = (node_t*) malloc(sizeof(node_t)); + if (result == NULL) + return NULL; + value = (int*) malloc(sizeof(int)); + if (value == NULL) { + free(result); + return NULL; + } + *value = random(); + + /* Store and return. */ + result->next = NULL; + result->data = value; + return result; +} + +/* This function generates a long list with random values in the nodes, returns NULL on failures. */ +/* Length denotes the length of the list. */ +linked_list_t* generate_long_random_list(int length) { + /* Sanity check. */ + if (length <= 0) + return NULL; + /* Variables. */ + linked_list_t *list; + node_t *current; + int i; + + /* Allocate the list. */ + list = initialize_linked_list(); + if (list == NULL) + return NULL; + + /* Fill the list with random nodes. */ + /* First node. */ + current = generate_random_node(); + if (current == NULL) { + free(list); + return NULL; + } + /* Attempt to append. */ + if (!append_node(list, current)) { + free(current->data); + free(current); + free(list); + return NULL; + } + /* Loop and add the rest. */ + for (i = 1; i < length; i++) { + /* Generate and attempt to append. */ + current = generate_random_node(); + if (!append_node(list, current)) { + /* Abort. */ + free(current->data); + free(current); + clear_list_data(&list, NULL); + return NULL; + } + } + + /* Update the list's length. */ + list->length = length; + /* Return the result. */ + return list; +} + +/* This function checks the actual length of a list. */ +int list_count_length(linked_list_t *list) { + if (list == NULL || list->head == NULL) + return 0; + /* Loop and count. */ + node_t *current = list->head; + int count = 0; + while (current != NULL) { + count++; + current = current->next; + } + /* Return the result. */ + return count; +} + +/* This function does the testing. */ +int test_linked_lists() { + /* Local variables. */ + linked_list_t *list; + node_t *node, *tail; + + /* Initialize an empty list. */ + list = initialize_linked_list(); + /* Check that it was correctly created. */ + assert(list != NULL); + assert(list->length == INITIAL_LIST_LENGTH); + assert(list->head == NULL); + + /* Generate and store the node. */ + node = generate_random_node(); + + /* Attempt to add it to the list. */ + append_node(list, node); + /* Check that the list grew and the head got set. */ + assert(list->length == LIST_LENGTH_ONE); + assert(list->head != NULL && list->head == node); + assert(get_node_i(list, 0) == node); + assert(get_node_index_pointer(list, node) == 0); + + /* Attempt to free the nodes and then the list. */ + remove_node_i_data(list, 0, NULL); + assert(list->length == INITIAL_LIST_LENGTH); + assert(list->head == NULL); + node = NULL; + free(list); + list = NULL; + + /* Attempt to allocate a long list. */ + list = generate_long_random_list(LIST_LENGTH_LONG_TEST); + if (list == NULL) { + printf(ERROR_TEXT_RANDOM_LIST_FAIL_ALLOCATION); + return 1; + } + assert(list->length == LIST_LENGTH_LONG_TEST); + assert(list->length == list_count_length(list)); + /* Test the get head/tail functions. */ + assert(get_node_head(list) == list->head); + tail = get_node_tail(list); + assert(tail != NULL && tail->next == NULL); + /* Test the indexer functions. */ + assert(get_node_index_pointer(list, tail) == (list->length - 1)); + /* Test the freeing functions. */ + clear_list_data(&list, NULL); + assert(list == NULL); + + /* Ran successfully, return 0. */ + return 0; +} diff --git a/tests/stack_tests.c b/tests/stack_tests.c new file mode 100644 index 0000000..237e789 --- /dev/null +++ b/tests/stack_tests.c @@ -0,0 +1,107 @@ +/* Include statements. */ +#include +#include +#include "../stack/stack.c" + +/* Define constants. */ +#define PRINT_INFO_TESTING_START "Starting tests.\n" +#define PRINT_INFO_TESTING_END "Done testing.\n" +#define SOME_TEST_FAILED "Recheck the tests, one of them failed!\n" +#define TEST_CODE_FAILURE "Error in test code, rerun!\n" +#define INITIAL_STACK_SIZE 0 +#define STACK_SIZE_ONE 1 +#define STACK_SIZE_TWO 2 +#define STACK_SIZE_LONG_TEST 4096 + + +/* Define functions. */ +node_t* generate_random_node(); +int test_stack(); + +/* Starting point. */ +int main() { + printf(PRINT_INFO_TESTING_START); + if(test_stack()) { + printf(TEST_CODE_FAILURE); + } + printf(PRINT_INFO_TESTING_END); +} + +/* This function generates a random number and puts it in a newly allocated node. */ +/* Caller has to free memory afterwards, returns NULL on failure. */ +node_t* generate_random_node() { + /* The node to return. */ + node_t* result; + int *value; + + /* Attempt to allocate the node. */ + result = (node_t*) malloc(sizeof(node_t)); + if (result == NULL) + return NULL; + value = (int*) malloc(sizeof(int)); + if (value == NULL) { + free(result); + return NULL; + } + *value = random(); + + /* Store and return. */ + result->next = NULL; + result->data = value; + return result; +} + +/* This function tests the workings of the stack structure. */ +/* Returns 0 on success. */ +int test_stack() { + /* Local variables. */ + stack_t *stack; + node_t *node; + int* value; + + /* Attempt to initialize the stack. */ + stack = initialize_stack(); + assert(stack != NULL); + assert(stack->size == INITIAL_STACK_SIZE); + assert(stack->head == NULL); + + /* Allocate and push a node. */ + node = generate_random_node(); + if (node == NULL) { + printf(TEST_CODE_FAILURE); + return 1; + } + if (!push(stack, node)) { + printf(SOME_TEST_FAILED); + return 1; + } + assert(stack->size == STACK_SIZE_ONE); + assert(stack->head != NULL); + assert(stack->head->next == NULL); + + /* Attempt to use the built-in node creation and push function. */ + value = (int*) malloc(sizeof(int)); + if (value == NULL) { + printf(SOME_TEST_FAILED); + return 1; + } + *value = 5; /* Random, chosen by fair dice roll. */ + if (!push_data(stack, value)) { + printf(SOME_TEST_FAILED); + return 1; + } + assert(stack->size == STACK_SIZE_TWO); + assert(stack->head != NULL); + assert(stack->head->next != NULL); + assert(stack_size(stack) == STACK_SIZE_TWO); + + /* Attempt to free. */ + free_stack_data(&stack, NULL); + assert(stack == NULL); + + /* Free the node. */ + //free(node); + + /* Success. */ + return 0; +} diff --git a/tests/stack_tests.c~ b/tests/stack_tests.c~ new file mode 100644 index 0000000..c461817 --- /dev/null +++ b/tests/stack_tests.c~ @@ -0,0 +1,107 @@ +/* Include statements. */ +#include +#include +#include "../stack/stack.c" + +/* Define constants. */ +#define PRINT_INFO_TESTING_START "Starting tests.\n" +#define PRINT_INFO_TESTING_END "Done testing.\n" +#define SOME_TEST_FAILED "Recheck the tests, one of them failed!\n" +#define TEST_CODE_FAILURE "Error in test code, rerun!\n" +#define INITIAL_STACK_SIZE 0 +#define STACK_SIZE_ONE 1 +#define STACK_SIZE_TWO 2 +#define STACK_SIZE_LONG_TEST 4096 + + +/* Define functions. */ +node_t* generate_random_node(); +int test_stack(); + +/* Starting point. */ +int main() { + printf(PRINT_INFO_TESTING_START); + if(test_stack()) { + printf(TEST_CODE_FAILURE); + } + printf(PRINT_INFO_TESTING_END); +} + +/* This function generates a random number and puts it in a newly allocated node. */ +/* Caller has to free memory afterwards, returns NULL on failure. */ +node_t* generate_random_node() { + /* The node to return. */ + node_t* result; + int *value; + + /* Attempt to allocate the node. */ + result = (node_t*) malloc(sizeof(node_t)); + if (result == NULL) + return NULL; + value = (int*) malloc(sizeof(int)); + if (value == NULL) { + free(result); + return NULL; + } + *value = random(); + + /* Store and return. */ + result->next = NULL; + result->data = value; + return result; +} + +/* This function tests the workings of the stack structure. */ +/* Returns 0 on success. */ +int test_stack() { + /* Local variables. */ + stack_t *stack; + node_t *node; + int* value; + + /* Attempt to initialize the stack. */ + stack = initialize_stack(); + assert(stack != NULL); + assert(stack->size == INITIAL_STACK_SIZE); + assert(stack->head == NULL); + + /* Allocate and push a node. */ + node = generate_random_node(); + if (node == NULL) { + printf(TEST_CODE_FAILURE); + return 1; + } + if (!push(stack, node)) { + printf(SOME_TEST_FAILED); + return 1; + } + assert(stack->size == STACK_SIZE_ONE); + assert(stack->head != NULL); + assert(stack->head->next == NULL); + + /* Attempt to use the built-in node creation and push function. */ + value = (int*) malloc(sizeof(int)); + if (value == NULL) { + printf(SOME_TEST_FAILED); + return 1; + } + *value = 5; /* Random, chosen by fair dice roll. */ + if (!push_data(stack, &value)) { + printf(SOME_TEST_FAILED); + return 1; + } + assert(stack->size == STACK_SIZE_TWO); + assert(stack->head != NULL); + assert(stack->head->next != NULL); + assert(stack_size(stack) == STACK_SIZE_TWO); + + /* Attempt to free. */ + free_stack_data(&stack, NULL); + assert(stack == NULL); + + /* Free the node. */ + //free(node); + + /* Success. */ + return 0; +} diff --git a/tests/tree_tests.c b/tests/tree_tests.c new file mode 100644 index 0000000..445faeb --- /dev/null +++ b/tests/tree_tests.c @@ -0,0 +1,274 @@ +/* Include statements. */ +#include +#include +#include "../trees/binary_tree.c" + +/* Define constants. */ +#define PRINT_INFO_TESTING_START "Starting tests.\n" +#define PRINT_INFO_TESTING_END "Done testing.\n" +#define ERROR_TEXT_RANDOM_LIST_FAIL_ALLOCATION "Long list test failed because of allocation errors!\n" +#define SOME_TEST_FAILED "Recheck the tests, one of them failed!\n" +#define TEST_INITIALIZE_TREE_NODE_SUCCESS "initialize_tree_node() passed tests!\n" +#define TEST_INITIALIZE_TREE_NODE_STORE_SUCCESS "initialized_tree_node_store() passed tests!\n" +#define TEST_TREE_NODE_LINK_SUCCESS "Tree node linking functions (left and right) passed tests!\n" +#define TEST_FREE_TREE_SUCCESS "free_tree() passed tests!\n" +#define ARRAY_START_POINT 0 +#define ARRAY_LENGTH_TREE_NODES 30 + +/* Define functions. */ +tree_node_t* generate_random_tree_node(); +int comparison_function_int(int *first, int *second); +tree_node_t* insert_sorted_array_into_tree(int *array, int start, int end); +tree_node_t* build_tree(int **arr); +int check_tree_bst(tree_node_t *root, int (*comparison_function)()); +int check_tree_build_data_free(); +int test_trees(); + +/* Starting point. */ +int main() { + printf(PRINT_INFO_TESTING_START); + if (test_trees()) { + printf(SOME_TEST_FAILED); + } + printf(PRINT_INFO_TESTING_END); +} + +/* This function generates a random number and puts it in a newly allocated node. */ +/* Caller has to free memory afterwards, returns NULL on failure. */ +tree_node_t* generate_random_tree_node() { + /* The node to return. */ + tree_node_t* result; + int *value; + + /* Attempt to allocate the node. */ + result = (tree_node_t*) malloc(sizeof(tree_node_t)); + if (result == NULL) + return NULL; + value = (int*) malloc(sizeof(int)); + if (value == NULL) { + free(result); + return NULL; + } + *value = random(); + + /* Store and return. */ + result->right = NULL; + result->left = NULL; + result->data = value; + return result; +} + +/* This function is used to compare two integers (given their pointers), exhibits undefined behaviour on NULL pointers. */ +int comparison_function_int(int *first, int *second) { + return *first == *second ? TREE_COMPARISON_EQUAL_TO : ((*first < *second) ? TREE_COMPARISON_SMALLER_THAN : TREE_COMPARISON_LARGER_THAN); +} + +/* This function will generate a balanced tree from the given sorted array, returns the root. */ +tree_node_t* insert_sorted_array_into_tree(int *array, int start, int end) { + /* Stop if start is larger than end. */ + if (start > end) + return NULL; + /* Find the middle point. */ + int middle = start + (end - start) / 2; + tree_node_t *root = initialize_tree_node_store(array + middle); + if (root == NULL) + return NULL; + root->left = insert_sorted_array_into_tree(array, start, middle - 1); + root->right = insert_sorted_array_into_tree(array, middle + 1, end); + return root; +} + +/* This function attempts to build a tree that is "sorted". */ +/* Will return NULL on failure. */ +tree_node_t* build_tree(int **arr) { + /* Local variables. */ + int *array; + int array_length = ARRAY_LENGTH_TREE_NODES - ARRAY_START_POINT; + + /* Allocate and populate array. */ + array = (int*) malloc(array_length * sizeof(int)); + if (array == NULL) { + *arr = NULL; + return NULL; + } + for (int i = ARRAY_START_POINT; i < ARRAY_LENGTH_TREE_NODES; i++) + array[i - ARRAY_START_POINT] = i; + /* Set the pointer back to the caller. */ + *arr = array; + + /* Return the resulting tree - END IS AN INDEX! */ + return insert_sorted_array_into_tree(array, 0, array_length - 1); +} + +/* This function checks that the given tree is a BST. */ +int check_tree_bst(tree_node_t *root, int (*comparison_function)()) { + /* Base case. */ + if (root == NULL || (root->right == NULL && root->left == NULL)) + return 1; + /* Only need to check the right side. */ + if (root->left == NULL) + return (((*comparison_function)(root, root->right) == TREE_COMPARISON_LARGER_THAN) && check_tree_bst(root->right, comparison_function)); + /* Only need to check the left side. */ + if (root->right == NULL) + return (((*comparison_function)(root, root->left) == TREE_COMPARISON_SMALLER_THAN) && check_tree_bst(root->left, comparison_function)); + /* Check both sides. */ + return (((*comparison_function)(root, root->right) == TREE_COMPARISON_LARGER_THAN) && ((*comparison_function)(root, root->left) == TREE_COMPARISON_SMALLER_THAN) && check_tree_bst(root->right, comparison_function) && check_tree_bst(root->left, comparison_function)); +} + +/* This function builds a tree then attempts to free it with the data thereof. */ +int check_tree_build_data_free(){ + /* Build a simple tree and try to free with data. */ + int *root_data, *left_data, *right_data; + tree_node_t *root, *left, *right; + + /* Allocate and fill the data. */ + root_data = (int*) malloc(sizeof(int)); + if (root_data == NULL) + return 1; + *root_data = 1; + left_data = (int*) malloc(sizeof(int)); + if (left_data == NULL) { + free(root_data); + return 1; + } + *left_data = 0; + right_data = (int*) malloc(sizeof(int)); + if (right_data == NULL) { + free(root_data); + free(left_data); + return 1; + } + *right_data = 2; + + /* Allocate and fill the nodes. */ + root = (tree_node_t*) malloc(sizeof(tree_node_t)); + if (root == NULL) { + free(root_data); + free(left_data); + free(right_data); + return 1; + } + root->data = root_data; + left = (tree_node_t*) malloc(sizeof(tree_node_t)); + if (left == NULL) { + free(root_data); + free(left_data); + free(right_data); + free(root); + return 1; + } + left->data = left_data; + right = (tree_node_t*) malloc(sizeof(tree_node_t)); + if (right == NULL) { + free(root_data); + free(left_data); + free(right_data); + free(root); + free(left); + return 1; + } + right->data = right_data; + + /* Link. */ + root->right = right; + root->left = left; + right->right = NULL; + right->left = NULL; + left->right = NULL; + left->left = NULL; + + /* Try to free with data. */ + free_tree_data(root, NULL); + return 0; +} + +/* This function does the testing. */ +int test_trees() { + /* Local variables. */ + tree_node_t *root, *right, *left; + int *first_value, *second_value, *array; + + /* Allocate the root. */ + root = initialize_tree_node(); + if (root == NULL) + return 1; + /* Assert that the left and right pointer are NULL, and the data is NULL too. */ + assert(root->right == NULL); + assert(root->left == NULL); + assert(root->data == NULL); + /* Print result. */ + printf(TEST_INITIALIZE_TREE_NODE_SUCCESS); + + /* Allocate two nodes with random values. */ + first_value = (int*) malloc(sizeof(int)); + second_value = (int*) malloc(sizeof(int)); + if (first_value == NULL || second_value == NULL) { + free(first_value); + free(second_value); + free(root); + return 1; + } + /* Generate right and left nodes. */ + right = initialize_tree_node_store(first_value); + left = initialize_tree_node_store(second_value); + if (right == NULL || left == NULL) { + free(first_value); + free(second_value); + free(right); + free(left); + free(root); + return 1; + } + assert(*((int*)right->data) == *first_value && *((int*)left->data) == *second_value); + /* 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); + assert(root->right == right); + assert(root->left == left); + /* Print result. */ + printf(TEST_TREE_NODE_LINK_SUCCESS); + /* Free tree, but not data. */ + free_tree(root); + assert(first_value != NULL && second_value != NULL); + /* Print the result. */ + printf(TEST_FREE_TREE_SUCCESS); + /* Free the data. */ + free(first_value); + first_value = NULL; + /* Free the nodes. */ + right = NULL; + left = NULL; + + /* Build the bigger tree. */ + root = build_tree(&array); + if (root == NULL) { + free(second_value); + return 1; + } + /* Verify that it is indeed a BST. */ + //assert(check_tree_bst(root, comparison_function_int) == 1); + /* Attempt to insert an extra node, check where it ends up. */ + *second_value = ARRAY_LENGTH_TREE_NODES; + right = initialize_tree_node_store(second_value); + if (right == NULL) { + free_tree_data(root, NULL); + free(second_value); + return 1; + } + /* Get the max node. */ + left = root; + while (left->right != NULL) + left = left->right; + /* Attach the node. */ + assert(insert_node_into_tree(root, right, comparison_function_int) == TREE_SUCCESS_CODE); + assert(left->right == right); + /* Cleanup. */ + free_tree(root); + free(array); + free(second_value); + + /* Ran successfully so far, return last test. */ + return check_tree_build_data_free(); +} diff --git a/tests/tree_tests.c~ b/tests/tree_tests.c~ new file mode 100644 index 0000000..db44e22 --- /dev/null +++ b/tests/tree_tests.c~ @@ -0,0 +1,274 @@ +/* Include statements. */ +#include +#include +#include "../trees/binary_tree.c" + +/* Define constants. */ +#define PRINT_INFO_TESTING_START "Starting tests.\n" +#define PRINT_INFO_TESTING_END "Done testing.\n" +#define ERROR_TEXT_RANDOM_LIST_FAIL_ALLOCATION "Long list test failed because of allocation errors!\n" +#define SOME_TEST_FAILED "Recheck the tests, one of them failed!\n" +#define TEST_INITIALIZE_TREE_NODE_SUCCESS "initialize_tree_node() passed tests!\n" +#define TEST_INITIALIZE_TREE_NODE_STORE_SUCCESS "initialized_tree_node_store() passed tests!\n" +#define TEST_TREE_NODE_LINK_SUCCESS "Tree node linking functions (left and right) passed tests!\n" +#define TEST_FREE_TREE_SUCCESS "free_tree() passed tests!\n" +#define ARRAY_START_POINT 0 +#define ARRAY_LENGTH_TREE_NODES 30 + +/* Define functions. */ +tree_node_t* generate_random_tree_node(); +int comparison_function_int(int *first, int *second); +tree_node_t* insert_sorted_array_into_tree(int *array, int start, int end); +tree_node_t* build_tree(int **arr); +int check_tree_bst(tree_node_t *root, int (*comparison_function)()); +int check_tree_build_data_free(); +int test_trees(); + +/* Starting point. */ +int main() { + printf(PRINT_INFO_TESTING_START); + if (test_trees()) { + printf(SOME_TEST_FAILED); + } + printf(PRINT_INFO_TESTING_END); +} + +/* This function generates a random number and puts it in a newly allocated node. */ +/* Caller has to free memory afterwards, returns NULL on failure. */ +tree_node_t* generate_random_tree_node() { + /* The node to return. */ + tree_node_t* result; + int *value; + + /* Attempt to allocate the node. */ + result = (tree_node_t*) malloc(sizeof(tree_node_t)); + if (result == NULL) + return NULL; + value = (int*) malloc(sizeof(int)); + if (value == NULL) { + free(result); + return NULL; + } + *value = random(); + + /* Store and return. */ + result->right = NULL; + result->left = NULL; + result->data = value; + return result; +} + +/* This function is used to compare two integers (given their pointers), exhibits undefined behaviour on NULL pointers. */ +int comparison_function_int(int *first, int *second) { + return *first == *second ? TREE_COMPARISON_EQUAL_TO : ((*first < *second) ? TREE_COMPARISON_SMALLER_THAN : TREE_COMPARISON_LARGER_THAN); +} + +/* This function will generate a balanced tree from the given sorted array, returns the root. */ +tree_node_t* insert_sorted_array_into_tree(int *array, int start, int end) { + /* Stop if start is larger than end. */ + if (start > end) + return NULL; + /* Find the middle point. */ + int middle = start + (end - start) / 2; + tree_node_t *root = initialize_tree_node_store(array + middle); + if (root == NULL) + return NULL; + root->left = insert_sorted_array_into_tree(array, start, middle - 1); + root->right = insert_sorted_array_into_tree(array, middle + 1, end); + return root; +} + +/* This function attempts to build a tree that is "sorted". */ +/* Will return NULL on failure. */ +tree_node_t* build_tree(int **arr) { + /* Local variables. */ + int *array; + int array_length = ARRAY_LENGTH_TREE_NODES - ARRAY_START_POINT; + + /* Allocate and populate array. */ + array = (int*) malloc(array_length * sizeof(int)); + if (array == NULL) { + *arr = NULL; + return NULL; + } + for (int i = ARRAY_START_POINT; i < ARRAY_LENGTH_TREE_NODES; i++) + array[i - ARRAY_START_POINT] = i; + /* Set the pointer back to the caller. */ + *arr = array; + + /* Return the resulting tree - END IS AN INDEX! */ + return insert_sorted_array_into_tree(array, 0, array_length - 1); +} + +/* This function checks that the given tree is a BST. */ +int check_tree_bst(tree_node_t *root, int (*comparison_function)()) { + /* Base case. */ + if (root == NULL || (root->right == NULL && root->left == NULL)) + return 1; + /* Only need to check the right side. */ + if (root->left == NULL) + return (((*comparison_function)(root, root->right) == TREE_COMPARISON_LARGER_THAN) && check_tree_bst(root->right, comparison_function)); + /* Only need to check the left side. */ + if (root->right == NULL) + return (((*comparison_function)(root, root->left) == TREE_COMPARISON_SMALLER_THAN) && check_tree_bst(root->left, comparison_function)); + /* Check both sides. */ + return (((*comparison_function)(root, root->right) == TREE_COMPARISON_LARGER_THAN) && ((*comparison_function)(root, root->left) == TREE_COMPARISON_SMALLER_THAN) && check_tree_bst(root->right, comparison_function) && check_tree_bst(root->left, comparison_function)); +} + +/* This function builds a tree then attempts to free it with the data thereof. */ +int check_tree_build_data_free(){ + /* Build a simple tree and try to free with data. */ + int *root_data, *left_data, *right_data; + tree_node_t *root, *left, *right; + + /* Allocate and fill the data. */ + root_data = (int*) malloc(sizeof(int)); + if (root_data == NULL) + return 1; + *root_data = 1; + left_data = (int*) malloc(sizeof(int)); + if (left_data == NULL) { + free(root_data); + return 1; + } + *left_data = 0; + right_data = (int*) malloc(sizeof(int)); + if (right_data == NULL) { + free(root_data); + free(left_data); + return 1; + } + *right_data = 2; + + /* Allocate and fill the nodes. */ + root = (tree_node_t*) malloc(sizeof(tree_node_t)); + if (root == NULL) { + free(root_data); + free(left_data); + free(right_data); + return 1; + } + root->data = root_data; + left = (tree_node_t*) malloc(sizeof(tree_node_t)); + if (left == NULL) { + free(root_data); + free(left_data); + free(right_data); + free(root); + return 1; + } + left->data = left_data; + right = (tree_node_t*) malloc(sizeof(tree_node_t)); + if (right == NULL) { + free(root_data); + free(left_data); + free(right_data); + free(root); + free(left); + return 1; + } + right->data = right_data; + + /* Link. */ + root->right = right; + root->left = left; + right->right = NULL; + right->left = NULL; + left->right = NULL; + left->left = NULL; + + /* Try to free with data. */ + free_tree_data(root, NULL); + return 0; +} + +/* This function does the testing. */ +int test_trees() { + /* Local variables. */ + tree_node_t *root, *right, *left; + int *first_value, *second_value, *array; + + /* Allocate the root. */ + root = initialize_tree_node(); + if (root == NULL) + return 1; + /* Assert that the left and right pointer are NULL, and the data is NULL too. */ + assert(root->right == NULL); + assert(root->left == NULL); + assert(root->data == NULL); + /* Print result. */ + printf(TEST_INITIALIZE_TREE_NODE_SUCCESS); + + /* Allocate two nodes with random values. */ + first_value = (int*) malloc(sizeof(int)); + second_value = (int*) malloc(sizeof(int)); + if (first_value == NULL || second_value == NULL) { + free(first_value); + free(second_value); + free(root); + return 1; + } + /* Generate right and left nodes. */ + right = initialize_tree_node_store(first_value); + left = initialize_tree_node_store(second_value); + if (right == NULL || left == NULL) { + free(first_value); + free(second_value); + free(right); + free(left); + free(root); + return 1; + } + assert(*((int*)right->data) == first_value && *((int*)left->data) == second_value); + /* 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); + assert(root->right == right); + assert(root->left == left); + /* Print result. */ + printf(TEST_TREE_NODE_LINK_SUCCESS); + /* Free tree, but not data. */ + free_tree(root); + assert(first_value != NULL && second_value != NULL); + /* Print the result. */ + printf(TEST_FREE_TREE_SUCCESS); + /* Free the data. */ + free(first_value); + first_value = NULL; + /* Free the nodes. */ + right = NULL; + left = NULL; + + /* Build the bigger tree. */ + root = build_tree(&array); + if (root == NULL) { + free(second_value); + return 1; + } + /* Verify that it is indeed a BST. */ + //assert(check_tree_bst(root, comparison_function_int) == 1); + /* Attempt to insert an extra node, check where it ends up. */ + *second_value = ARRAY_LENGTH_TREE_NODES; + right = initialize_tree_node_store(second_value); + if (right == NULL) { + free_tree_data(root, NULL); + free(second_value); + return 1; + } + /* Get the max node. */ + left = root; + while (left->right != NULL) + left = left->right; + /* Attach the node. */ + assert(insert_node_into_tree(root, right, comparison_function_int) == TREE_SUCCESS_CODE); + assert(left->right == right); + /* Cleanup. */ + free_tree(root); + free(array); + free(second_value); + + /* Ran successfully so far, return last test. */ + return check_tree_build_data_free(); +} diff --git a/trees/binary_tree.c b/trees/binary_tree.c new file mode 100644 index 0000000..cb893bb --- /dev/null +++ b/trees/binary_tree.c @@ -0,0 +1,144 @@ +/* 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, free_function); + root->right = NULL; + } + if (root->left != NULL) { + free_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); +} + +/* 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; +} diff --git a/trees/binary_tree.c~ b/trees/binary_tree.c~ new file mode 100644 index 0000000..ff4ca30 --- /dev/null +++ b/trees/binary_tree.c~ @@ -0,0 +1,144 @@ +/* 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; +} diff --git a/trees/binary_tree.h b/trees/binary_tree.h new file mode 100644 index 0000000..453a2ad --- /dev/null +++ b/trees/binary_tree.h @@ -0,0 +1,22 @@ +/* This file defines a simple binary tree and related functions thereof. */ +#include +#ifndef BINARY_TREE_H +#define BINARY_TREE_H +#include "../nodes/tree_node.h" + +/* Define all the functions. */ +/* This function initializes a single node. */ +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); +/* This function links a node to the right. */ +int link_tree_node_right(tree_node_t *parent, tree_node_t *child); +/* This function links a node to the left. */ +int link_tree_node_left(tree_node_t *parent, tree_node_t *child); +/* This function frees a whole tree - not including data. */ +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)()); +/* This function inserts data to the tree. */ +int insert_node_into_tree(tree_node_t *root, tree_node_t *to_insert, int (*comparison_function)()); +#endif /* BINARY_TREE_H */ diff --git a/trees/binary_tree.h~ b/trees/binary_tree.h~ new file mode 100644 index 0000000..862c510 --- /dev/null +++ b/trees/binary_tree.h~ @@ -0,0 +1,22 @@ +/* This file defines a simple binary tree and related functions thereof. */ +#include +#ifndef BINARY_TREE_H +#define BINARY_TREE_H +#include "../nodes/tree_node.h" + +/* Define all the functions. */ +/* This function initializes a single node. */ +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); +/* This function links a node to the right. */ +int link_tree_node_right(tree_node_t *parent, tree_node_t *child); +/* This function links a node to the left. */ +int link_tree_node_left(tree_node_t *parent, tree_node_t *child); +/* This function frees a whole tree - not including data. */ +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); +/* This function inserts data to the tree. */ +int insert_node_into_tree(tree_node_t *root, tree_node_t *to_insert, void *comparison_function); +#endif /* BINARY_TREE_H */ diff --git a/useful_gcc_flags b/useful_gcc_flags new file mode 100644 index 0000000..0145194 --- /dev/null +++ b/useful_gcc_flags @@ -0,0 +1,3 @@ +-g debug +-fsanitize=address memory leaks +-Wall warnings