Initial Commit
This commit is contained in:
commit
72f3ae3164
|
@ -0,0 +1,70 @@
|
|||
/* This header defines a single-linked-list and related functions. */
|
||||
/* Use the single nodes. */
|
||||
#include <stdlib.h>
|
||||
#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 */
|
|
@ -0,0 +1,66 @@
|
|||
/* This header defines a single-linked-list and related functions. */
|
||||
/* Use the single nodes. */
|
||||
#include <stdlib.h>
|
||||
#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 */
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* This header defines a single-linked-list and related functions. */
|
||||
/* Use the single nodes. */
|
||||
#include <stdlib.h>
|
||||
#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 */
|
|
@ -0,0 +1,66 @@
|
|||
/* This header defines a single-linked-list and related functions. */
|
||||
/* Use the single nodes. */
|
||||
#include <stdlib.h>
|
||||
#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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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;
|
|
@ -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 */
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 <stdlib.h>
|
||||
/* 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*/
|
|
@ -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 <stdlib.h>
|
||||
/* 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*/
|
|
@ -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
|
|
@ -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
|
|
@ -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 <string.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_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 <string.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_H
|
Binary file not shown.
|
@ -0,0 +1,170 @@
|
|||
/* Include statements. */
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
/* Include statements. */
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/* Include statements. */
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/* Include statements. */
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/* Include statements. */
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#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();
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/* Include statements. */
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#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();
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/* This file defines a simple binary tree and related functions thereof. */
|
||||
#include <stdlib.h>
|
||||
#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 */
|
|
@ -0,0 +1,22 @@
|
|||
/* This file defines a simple binary tree and related functions thereof. */
|
||||
#include <stdlib.h>
|
||||
#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 */
|
|
@ -0,0 +1,3 @@
|
|||
-g debug
|
||||
-fsanitize=address memory leaks
|
||||
-Wall warnings
|
Loading…
Reference in New Issue