1
0
Fork 0
C_lib/linked_lists/single_linked_list.c

482 lines
16 KiB
C

/*
* C_lib Copyright (C) 2021 Wael Karram.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/* 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_single_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_single_linked_list(linked_list_t *list, node_t *node) {
/* Input sanity check. */
if (list == NULL || node == NULL)
return FAILURE_CODE_SIGNLE_LINKED_LIST_C;
/* Set the next to NULL. */
node->next = NULL;
/* 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_single_linked_list(linked_list_t *list, node_t *node) {
/* Input sanity check. */
if (list == NULL || node == NULL)
return FAILURE_CODE_SIGNLE_LINKED_LIST_C;
/* Set the next to NULL. */
node->next = NULL;
/* 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_single_linked_list(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_single_linked_list(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_single_linked_list(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_single_linked_list(list, node);
}
/* This function inserts a node at the ith place, returns 1 on success and 0 on failure. */
int add_node_i_single_linked_list(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;
/* Set the next to NULL. */
node->next = NULL;
/* 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_single_linked_list(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_single_linked_list(list, node, i);
}
/* This function reads the data at the ith node, returns NULL on failure or NULL data! */
/* Sets the error code in error (instead of returning it). */
void* read_node_i_single_linked_list(linked_list_t *list, int i, int *error) {
/* Input sanity check. */
if (error == NULL)
return NULL;
if (list == NULL || list->length <= i) {
*error = FAILURE_CODE_SIGNLE_LINKED_LIST_C;
return NULL;
}
/* Loop and read. */
node_t *current = list->head;
for (; i > 0; i--)
current = current->next;
/* Set the error code. */
*error = SUCCESS_CODE_SIGNLE_LINKED_LIST_C;
/* 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. */
/* Sets the error code in error (instead of returning it). */
node_t* get_node_i_single_linked_list(linked_list_t *list, int i, int *error) {
/* Input sanity check */
if (error == NULL)
return NULL;
if (list == NULL || list->length <= i) {
*error = FAILURE_CODE_SIGNLE_LINKED_LIST_C;
return NULL;
}
/* Loop. */
node_t *current = list->head;
for (; i > 0; i--)
current = current->next;
/* Set the error code. */
*error = SUCCESS_CODE_SIGNLE_LINKED_LIST_C;
/* 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 not found. */
int get_node_index_pointer_single_linked_list(linked_list_t *list, node_t *node){
/* Sanity check. */
if (list == NULL || node == NULL)
return INVALID_INPUT_CODE_SINGLE_LINKED_LIST_C;
/* Local variables. */
node_t *current;
int i = 0;
/* Attempt to search. */
if (list->head == NULL)
return INDEX_NOT_FOUND_CODE_SINGLE_LINKED_LIST_C;
current = list->head;
while (current != NULL && current != node) {
current = current->next;
i++;
}
/* Check if we found it or not. */
return (i >= list->length) ? INDEX_NOT_FOUND_CODE_SINGLE_LINKED_LIST_C : i;
}
/* This function attempts to find the index of a given node, by data. */
/* Returns -2 on invalid input, and -1 when not found. */
int get_node_index_data_single_linked_list(linked_list_t *list, void *data, int (*comparison_function)(const void*, const void*)) {
/* Sanity check. */
if (list == NULL || comparison_function == NULL)
return INVALID_INPUT_CODE_SINGLE_LINKED_LIST_C;
/* Local variables. */
node_t *current;
int i = 0;
/* Check if there is anything to search in the first place. */
if (list->head == NULL)
return INDEX_NOT_FOUND_CODE_SINGLE_LINKED_LIST_C;
/* Set the start. */
current = list->head;
/* Attempt to search. */
while (current != NULL && comparison_function(data, current->data) != 0) {
current = current->next;
i++;
}
/* Check if we found it or not. */
return (i >= list->length) ? INDEX_NOT_FOUND_CODE_SINGLE_LINKED_LIST_C : i;
}
/* This function deletes the ith node, returns 1 on success and 0 on failure. */
int remove_node_i_single_linked_list(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_single_linked_list(linked_list_t *list, int i, void (*free_function)(void*)) {
/* 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. */
/* Sets the error code in error (instead of returning it). */
void* read_node_head_single_linked_list(linked_list_t *list, int *error) {
/* Delegate. */
return read_node_i_single_linked_list(list, INDEX_HEAD_SINGLE_LINKED_LIST_C, error);
}
/* This function retrieves the first node, note that it will return NULL on invalid input or first node being NULL. */
/* Sets the error code in error (instead of returning it). */
node_t* get_node_head_single_linked_list(linked_list_t *list, int *error) {
/* Delegate. */
return get_node_i_single_linked_list(list, INDEX_HEAD_SINGLE_LINKED_LIST_C, error);
}
/* This function deletes the first node, returns 1 on success and 0 on failure. */
int remove_node_head_single_linked_list(linked_list_t *list) {
/* Delegate. */
return remove_node_i_single_linked_list(list, INDEX_HEAD_SINGLE_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_single_linked_list(linked_list_t *list, void (*free_function)(void*)) {
/* Delegate. */
return remove_node_i_data_single_linked_list(list, INDEX_HEAD_SINGLE_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. */
/* Sets the error code in error (instead of returning it). */
void* read_node_tail_single_linked_list(linked_list_t *list, int *error) {
/* Sanity check. */
if (error == NULL)
return NULL;
if (list == NULL || list->head == NULL)
return FAILURE_CODE_SIGNLE_LINKED_LIST_C;
/* Delegate. */
return read_node_i_single_linked_list(list, list->length - 1, error);
}
/* This function retrieves the last node, will return NULL on invalid input or the first node being NULL. */
/* Sets the error code in error (instead of returning it). */
node_t* get_node_tail_single_linked_list(linked_list_t *list, int *error) {
/* Sanity check. */
if (error == NULL)
return NULL;
if (list == NULL || list->head == NULL)
return FAILURE_CODE_SIGNLE_LINKED_LIST_C;
/* Delegate. */
return get_node_i_single_linked_list(list, list->length - 1, error);
}
/* This function deletes the last node, returns 1 on success and 0 on failure. */
int remove_node_tail_single_linked_list(linked_list_t *list) {
/* Sanity check. */
if (list == NULL || list->head == NULL)
return FAILURE_CODE_SIGNLE_LINKED_LIST_C;
/* Delegate. */
return remove_node_i_single_linked_list(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_single_linked_list(linked_list_t *list, void (*free_function)(void*)) {
/* Sanity check. */
if (list == NULL || list->head == NULL)
return FAILURE_CODE_SIGNLE_LINKED_LIST_C;
/* Delegate. */
return remove_node_i_data_single_linked_list(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_single_linked_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_SINGLE_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_single_linked_list(linked_list_t **list, void (*free_function)(void*)) {
/* 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_SINGLE_LINKED_LIST_C;
}
/* This function attetmps to serialize a linked list into an array. */
/* The function will allocate and return a pointer to said array on success, NULL on failure. */
/* The length of the array is sent through the length pointer, and set to -1 on failure. */
void **serialize_linked_list(linked_list_t *list, int *length) {
/* Local variables. */
void **array;
node_t *current;
int i;
/* Sanity check. */
if (list == NULL || list->head == NULL || length == NULL || list->length <= 0)
return NULL;
/* Set the length. */
*length = list->length;
/* Attempt to allocate the array. */
array = (void**) malloc((*length) * sizeof(void*));
/* Check for allocation failure. */
if (array == NULL) {
*length = -1;
return NULL;
}
/* Fill the array. */
current = list->head;
for (i = 0; i < *length; i++) {
array[i] = current->data;
current = current->next;
}
/* Return the result. */
return array;
}