1
0
Fork 0

Initial Commit

This commit is contained in:
wael 2021-08-29 17:26:31 +03:00
commit 72f3ae3164
32 changed files with 2915 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

12
nodes/double_node.h Normal file
View File

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

12
nodes/double_node.h~ Normal file
View File

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

10
nodes/single_node.h Normal file
View File

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

7
nodes/single_node.h~ Normal file
View File

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

12
nodes/tree_node.h Normal file
View File

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

12
nodes/tree_node.h~ Normal file
View File

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

130
stack/stack.c Normal file
View File

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

130
stack/stack.c~ Normal file
View File

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

41
stack/stack.h Normal file
View File

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

41
stack/stack.h~ Normal file
View File

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

21
strings/strzcpy.c Normal file
View File

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

18
strings/strzcpy.c~ Normal file
View File

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

16
strings/strzcpy.h Normal file
View File

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

15
strings/strzcpy.h~ Normal file
View File

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

BIN
tests/a.out Executable file

Binary file not shown.

View File

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

View File

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

107
tests/stack_tests.c Normal file
View File

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

107
tests/stack_tests.c~ Normal file
View File

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

274
tests/tree_tests.c Normal file
View File

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

274
tests/tree_tests.c~ Normal file
View File

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

144
trees/binary_tree.c Normal file
View File

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

144
trees/binary_tree.c~ Normal file
View File

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

22
trees/binary_tree.h Normal file
View File

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

22
trees/binary_tree.h~ Normal file
View File

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

3
useful_gcc_flags Normal file
View File

@ -0,0 +1,3 @@
-g debug
-fsanitize=address memory leaks
-Wall warnings