From 8b246c97740e8d651735df8992dd8c6dd22ddce2 Mon Sep 17 00:00:00 2001 From: MarcUs7i Date: Wed, 9 Apr 2025 08:31:55 +0200 Subject: [PATCH] finished --- advanced_singly_linked_list.c | 432 +++++++++++++++++++++++++++++++++- advanced_singly_linked_list.h | 2 +- queue.c | 148 +++++++++++- queue.h | 21 +- stack.c | 144 +++++++++++- stack.h | 23 +- 6 files changed, 739 insertions(+), 31 deletions(-) diff --git a/advanced_singly_linked_list.c b/advanced_singly_linked_list.c index eea9e93..53ad28b 100644 --- a/advanced_singly_linked_list.c +++ b/advanced_singly_linked_list.c @@ -1,9 +1,9 @@ /*---------------------------------------------------------- - * HTBLA-Leonding / Class: + * HTBLA-Leonding / Class: 2IHIF * --------------------------------------------------------- * Exercise Number: S03 * Title: Advanced Singly Linked List implementation - * Author: */;/* + * Author: Marc Tismonar * ---------------------------------------------------------- * Description: * Implementation of an advanced singly linked list. @@ -40,25 +40,449 @@ /* add includes as needed */ +#include #include "config.h" #include "allocator.h" /** The type of list nodes */ +typedef struct IntListNodeData* IntListNode; /** The implementation of list node data */ +struct IntListNodeData { + int data; + IntListNode next; +}; /** The implementation of list data: head, tail, size! */ +struct IntListData { + IntListNode head; + IntListNode tail; + int size; +}; /* ===================================================================== */ /* private list functions */ -static IntNode list_obtain_node(int value) { +static IntListNode list_obtain_node(int data) { + IntListNode node = (IntListNode)alloc_mem(sizeof(struct IntListNodeData)); + node->data = data; + node->next = 0; + return node; } -static void list_release_node(IntNode* node) { +static void list_release_node(IntListNode node) { + free_mem(node); + node = 0; } /* ===================================================================== */ + +/** + * Obtains ('creates') and provides a 'new' list instance. + * Any list obtained via this function MUST be released using + * function `release_list()`. + * + * Note: This function does not make any assumptions + * about how list components, esp. nodes, are allocated. + * + * @return IntList The list instance or 0, if no list could by instantiated. + */ +IntList list_obtain() { + IntList intList = (IntList)alloc_mem(sizeof(struct IntListData)); + if (intList != 0) { + intList->head = 0; + intList->tail = 0; + intList->size = 0; + } + return intList; +} + +/** + * Releases a list that was obtained earlier via function `obtain_list`. + * Released lists MUST NOT be used anymore. + * + * Note: The implementation of this function does not make any assumptions + * about the allocation method of list elements, but MUST match the implementation + * of function `obtain_list` as its inverse function. + * + * @param p_list The pointer to the list to release. The value of the pointer + * is set to 0, if the list was successfully released, otherwise it is left untouched. + */ +void list_release(IntList* p_list) { // no need to use the tail & size as its going to free everything anyways + if (p_list == 0 || *p_list == 0) { + return; + } + + IntList list = *p_list; + IntListNode current = list->head; + + while (current != 0) { + IntListNode next = current->next; + list_release_node(current); + current = next; + } + + free_mem(list); + *p_list = 0; +} + +/** + * Determines whether or not the given list is valid. + * + * @param list The list to evaluate. + * @return `True` if the list is valid, false otherwise. + */ +bool list_is_valid(IntList list) { + return list != 0; +} + +/** + * Determines whether or not the list contains at least one item. + * + * @param list The list to evaluate. + * @return `False` if the list contains one or more items, `true` otherwise. + */ +bool list_is_empty(IntList list) { + if (!list_is_valid(list)) { + return true; + } + + return list->head == 0 && list->tail == 0 && list->size == 0; +} + +/** + * Provides the number of values stored in the list. + * + * @param list The list to evaluate. + * @return The number of values the list contains. + */ +int list_get_size(IntList list) { + if(!list_is_valid(list)) { + return 0; + } + + return list->size; +} + +/** + * Determines whether or not the list given list contains the queried value + * at least once. + * + * @param list The list to query. + * @param value The value. + * @return `True` if the list contains at least one instance of the value, + * `false ` otherwise. + */ +bool list_contains(IntList list, int value) { + if (!list_is_valid(list)) { + return false; + } + + IntListNode current = list->head; + while (current != 0) { + if (current->data == value) { + return true; + } + current = current->next; + } + + return false; +} + +/** + * Provides the value stored in the list at the given position. + * + * @param list The list from which the value shall be retrieved. + * @param index The zero-based position index of the value to retrieve. + * @return The value stored at the given position or 0, if the position + * is not available. + */ +int list_get_at(IntList list, unsigned int index) { + if (!list_is_valid(list) || list_is_empty(list)) { + return 0; + } + + if (index < list->size) { + IntListNode current = list->head; + for(unsigned int i = 0; i < index; i++) { + current = current->next; + } + return current->data; + } + + return 0; +} + +/** + * Inserts the given value at the end of the given list. + * + * @param list The list to which the value shall be appended. + * @param value The value to append to the list. + */ +void list_insert(IntList list, int value) { + if (!list_is_valid(list)) { + return; + } + + IntListNode newNode = list_obtain_node(value); + + if (newNode != 0) { + if (list_is_empty(list)) { + list->head = newNode; + } else { + list->tail->next = newNode; + } + } + + list->tail = newNode; + list->size++; +} + +/** + * Inserts the given value at the indexed position in a way the + * the inserted value is on that position. The index is + * - similar to arrays - zero-based. If the the list is shorter + * than the indexed position, the value is inserted at the end + * of the list. + * + * @param list The list into which the value shall be appended. + * @param index The position index of the value to insert. + * @param value The value to insert. + */ +void list_insert_at(IntList list, unsigned int index, int value) { + if (!list_is_valid(list)) { + return; + } + + IntListNode newNode = list_obtain_node(value); + if (newNode == 0) { + return; + } + + if (list_is_empty(list)) { + list->head = newNode; + list->tail = newNode; + list->size++; + return; + } + + if (index == 0) { + newNode->next = list->head; + list->head = newNode; + list->size++; + return; + } + + IntListNode current = list->head; + for (unsigned int i = 0; i < index - 1 && current->next != 0; i++) { + current = current->next; + } + + if (current->next == 0) { + current->next = newNode; + list->tail = newNode; + } + else { + newNode->next = current->next; + current->next = newNode; + } + + list->size++; +} + +/** + * Appends the `list_to_append` at the end of the given `list`. + * The appended list is empty afterwards, because all nodes of that list + * have been transferred to `list`. + * + * @param list The list that receives the other list. + * @param list_to_append The list that is appended to `list`. + */ +void list_append(IntList list, IntList list_to_append) { + if (!list_is_valid(list) || !list_is_valid(list_to_append) || list_is_empty(list_to_append)) { + return; + } + + if (list_is_empty(list)) { + list->head = list_to_append->head; + list->tail = list_to_append->tail; + list->size = list_to_append->size; + } else { + list->tail->next = list_to_append->head; + list->tail = list_to_append->tail; + list->size += list_to_append->size; + } + + list_to_append->head = 0; + list_to_append->tail = 0; + list_to_append->size = 0; +} + +/** + * Removes the first occurrance of `value` from the given list. + * If the list does not contain that value, the list shall not + * be modified. + * + * @param list The list from which the given value shall be removed. + * @param value The value to remove from the list. + */ +void list_remove(IntList list, int value) { + if (!list_is_valid(list) || list_is_empty(list)) { + return; + } + + if (list->head->data == value) { + IntListNode old_head = list->head; + list->head = list->head->next; + + // If list becomes empty, update tail + if (list->head == 0) { + list->tail = 0; + } + + list_release_node(old_head); + list->size--; + return; + } + + for (IntListNode current = list->head; current->next != 0; current = current->next) { + if (current->next->data == value) { + IntListNode to_remove = current->next; + current->next = to_remove->next; + + if (to_remove == list->tail) { + list->tail = current; + } + + list_release_node(to_remove); + list->size--; + return; + } + } +} + +/** + * Removes all occurrances of `value` from the list. + * If the list does not contain that value, the list shall not + * be modified. + * + * @param list The list from which all occurrances of `value` shall be removed. + * @param value The `value` to remove throughout the list. + */ +void list_remove_all(IntList list, int value) { + if (!list_is_valid(list) || list_is_empty(list)) { + return; + } + + while (list->head != 0 && list->head->data == value) { + IntListNode old_head = list->head; + list->head = list->head->next; + + if (list->head == 0) { + list->tail = 0; + } + + list_release_node(old_head); + list->size--; + } + + if (list_is_empty(list)) { + return; + } + + IntListNode prev = list->head; + IntListNode current = list->head->next; + + while (current != 0) { + if (current->data == value) { + prev->next = current->next; + + if (current == list->tail) { + list->tail = prev; + } + + IntListNode to_remove = current; + current = current->next; + + list_release_node(to_remove); + list->size--; + } else { + prev = current; + current = current->next; + } + } +} + +/** + * Removes the value at the indexed position from the given list + * and provides that value. If the list does not have a value + * at that position, the list remains unmodified. + * + * @param list The list from which the value at the given index shall be returned. + * @param index The zero-based index of the value to return. + * @return The removed value or 0 in case of errors. + */ +int list_remove_at(IntList list, unsigned int index) { + if (!list_is_valid(list) || list_is_empty(list) || index >= list->size) { + return 0; + } + + int value; + + if (index == 0) { + value = list->head->data; + IntListNode old_head = list->head; + list->head = list->head->next; + + if (list->head == 0) { + list->tail = 0; + } + + list_release_node(old_head); + list->size--; + return value; + } + + IntListNode current = list->head; + for (unsigned int i = 0; i < index - 1; i++) { + current = current->next; + } + + IntListNode to_remove = current->next; + value = to_remove->data; + + current->next = to_remove->next; + + if (to_remove == list->tail) { + list->tail = current; + } + + list_release_node(to_remove); + list->size--; + return value; +} + +/** + * Clears the given list by removing all values from the list. + * + * @param list The list to clear. + */ +void list_clear(IntList list) { + if (!list_is_valid(list) || list_is_empty(list)) { + return; + } + + IntListNode current = list->head; + while (current != 0) { + IntListNode next = current->next; + list_release_node(current); + current = next; + } + + list->head = 0; + list->tail = 0; + list->size = 0; +} \ No newline at end of file diff --git a/advanced_singly_linked_list.h b/advanced_singly_linked_list.h index d988748..a3f9092 100644 --- a/advanced_singly_linked_list.h +++ b/advanced_singly_linked_list.h @@ -1,5 +1,5 @@ /*---------------------------------------------------------- - * HTBLA-Leonding / Class: + * HTBLA-Leonding / Class: 2IHIF * --------------------------------------------------------- * Exercise Number: S03 * Title: Advanced Singly Linked List diff --git a/queue.c b/queue.c index 101fc8e..87e83d5 100644 --- a/queue.c +++ b/queue.c @@ -1,9 +1,9 @@ /*---------------------------------------------------------- - * HTBLA-Leonding / Class: + * HTBLA-Leonding / Class: 2IHIF * --------------------------------------------------------- * Exercise Number: S03 * Title: Queue implementation - * Author: */;/* + * Author: Marc Tismonar * ---------------------------------------------------------- * Description: * Implementation of a queue based on an advanced singly linked list. @@ -31,10 +31,154 @@ */ /* includes */ +#include +#include "queue.h" +#include "advanced_singly_linked_list.h" +#include "allocator.h" /** The implementation of queue data */ +struct IntQueueData { + IntList list; +}; /* ===================================================================== */ /* private queue functions */ /* ===================================================================== */ + +/** + * Obtains ('creates') and provides a 'new' queue instance. + * Any queue obtained via this function MUST be released using + * function `release_queue()`. + * + * Note: This function does not make any assumptions + * about how queue components, esp. nodes, are allocated. + * + * @return IntQueue The queue instance or 0, if no queue could by instantiated. + */ +IntQueue queue_obtain() { + IntQueue queue = (IntQueue)alloc_mem(sizeof(struct IntQueueData)); + if (queue != 0) { + queue->list = list_obtain(); + } + + return queue; +} + +/** + * Releases a queue that was obtained earlier via function `obtain_queue`. + * Released queues MUST NOT be used anymore. + * + * Note: The implementation of this function does not make any assumptions + * about the allocation method of queue elements, but MUST match the implementation + * of function `obtain_queue` as its inverse function. + * + * @param p_queue The pointer to the queue to release. The value of the pointer + * is set to 0, if the queue was successfully released, otherwise it is left untouched. + */ +IntQueue queue_release(IntQueue* p_queue) { + if (p_queue == 0 || *p_queue == 0) { + return 0; + } + + IntQueue queue = *p_queue; + list_release(&queue->list); + free_mem(queue); + *p_queue = 0; + + return queue; +} + +/** + * Determines whether or not the given queue is valid. + * + * @param queue The queue to evaluate. + * @return `True` if the queue is valid, false otherwise. + */ +bool queue_is_valid(IntQueue queue) { + return queue != 0 && queue->list != 0; +} + +/** + * Determines whether or not the queue contains at least one item. + * + * @param queue The queue to evaluate. + * @return `False` if the queue contains one or more items, `true` otherwise. + */ +bool queue_is_empty(IntQueue queue) { + return !queue_is_valid(queue) || list_is_empty(queue->list); +} + +/** + * Provides the number of values stored in the queue. + * + * @param queue The queue to evaluate. + * @return The number of values the queue contains. + */ +int queue_get_size(IntQueue queue) { + if (!queue_is_valid(queue)) { + return 0; + } + + return list_get_size(queue->list); +} + +/** + * Clears the given queue by removing all values from the queue. + * + * @param queue The queue to clear. + */ +void queue_clear(IntQueue queue) { + if (!queue_is_valid(queue)) { + return; + } + + list_clear(queue->list); +} + +/** + * Inserts the given value to the queue (as new tail). + * + * @param queue The queue to which the value shall be appended. + * @param value The value to append to the queue. + */ +void queue_enqueue(IntQueue queue, int value) +{ + if (!queue_is_valid(queue)) { + return; + } + + list_insert(queue->list, value); +} + +/** + * Provides the value that 'dequeue' would provided but WITHOUT removing + * this value from the queue. + * + * @param queue The queue from which the value shall be peeked. + * @return The next value or 0, if the queue is empty. + */ +int queue_peek(IntQueue queue) { + if (!queue_is_valid(queue)) { + return 0; + } + + return list_get_at(queue->list, 0); +} + +/** + * Provides AND removes the next value from the queue. + * + * @param queue The queue from which the value shall be removed and returned. + * @return The value or 0, if the queue is empty. + */ +int queue_dequeue(IntQueue queue) { + if (!queue_is_valid(queue)) { + return 0; + } + + int value = list_get_at(queue->list, 0); + list_remove_at(queue->list, 0); + return value; +} + diff --git a/queue.h b/queue.h index 76372a0..5be0402 100644 --- a/queue.h +++ b/queue.h @@ -3,7 +3,7 @@ * --------------------------------------------------------- * Exercise Number: S03 * Title: Queue Inteface - * Author: */;/* + * Author: Marc Tismonar * ---------------------------------------------------------- * Description: * The declaration of a queue abstract data type. @@ -14,6 +14,7 @@ #include /** The type of the integer queue: IntQueue. */ +typedef struct IntQueueData* IntQueue; /** * Obtains ('creates') and provides a 'new' queue instance. @@ -25,7 +26,7 @@ * * @return IntQueue The queue instance or 0, if no queue could by instantiated. */ - queue_obtain(); +IntQueue queue_obtain(); /** * Releases a queue that was obtained earlier via function `obtain_queue`. @@ -38,7 +39,7 @@ * @param p_queue The pointer to the queue to release. The value of the pointer * is set to 0, if the queue was successfully released, otherwise it is left untouched. */ - queue_release(); +IntQueue queue_release(IntQueue* p_queue); /** * Determines whether or not the given queue is valid. @@ -46,7 +47,7 @@ * @param queue The queue to evaluate. * @return `True` if the queue is valid, false otherwise. */ - queue_is_valid(); +bool queue_is_valid(IntQueue queue); /** * Determines whether or not the queue contains at least one item. @@ -54,7 +55,7 @@ * @param queue The queue to evaluate. * @return `False` if the queue contains one or more items, `true` otherwise. */ - queue_is_empty(); +bool queue_is_empty(IntQueue queue); /** * Provides the number of values stored in the queue. @@ -62,14 +63,14 @@ * @param queue The queue to evaluate. * @return The number of values the queue contains. */ - queue_get_size(I); +int queue_get_size(IntQueue queue); /** * Clears the given queue by removing all values from the queue. * * @param queue The queue to clear. */ - queue_clear(); +void queue_clear(IntQueue queue); /** * Inserts the given value to the queue (as new tail). @@ -77,7 +78,7 @@ * @param queue The queue to which the value shall be appended. * @param value The value to append to the queue. */ - queue_enqueue(); +void queue_enqueue(IntQueue queue, int value); /** * Provides the value that 'dequeue' would provided but WITHOUT removing @@ -86,7 +87,7 @@ * @param queue The queue from which the value shall be peeked. * @return The next value or 0, if the queue is empty. */ - queue_peek(); +int queue_peek(IntQueue queue); /** * Provides AND removes the next value from the queue. @@ -94,5 +95,5 @@ * @param queue The queue from which the value shall be removed and returned. * @return The value or 0, if the queue is empty. */ - queue_dequeue(); +int queue_dequeue(IntQueue queue); diff --git a/stack.c b/stack.c index e91aa57..441fbc8 100644 --- a/stack.c +++ b/stack.c @@ -1,9 +1,9 @@ /*---------------------------------------------------------- - * HTBLA-Leonding / Class: + * HTBLA-Leonding / Class: 2IHIF * --------------------------------------------------------- * Exercise Number: S03 * Title: Stack implementation - * Author: */;/* + * Author: Marc Tismonar * ---------------------------------------------------------- * Description: * Implementation of a stack based on an advanced singly linked list. @@ -31,12 +31,150 @@ */ /* includes */ +#include +#include "stack.h" +#include "advanced_singly_linked_list.h" +#include "allocator.h" /** The implementation of stack data */ - +struct IntStackData { + IntList list; +}; /* ===================================================================== */ /* private stack functions */ /* ===================================================================== */ +/** + * Obtains ('creates') and provides a 'new' stack instance. + * Any stack obtained via this function MUST be released using + * function `release_stack()`. + * + * Note: This function does not make any assumptions + * about how stack components, esp. nodes, are allocated. + * + * @return IntStack The stack instance or 0, if no stack could by instantiated. + */ +IntStack stack_obtain() { + IntStack stack = (IntStack)alloc_mem(sizeof(struct IntStackData)); + if (stack != 0) { + stack->list = list_obtain(); + } + + return stack; +} + +/** + * Releases a stack that was obtained earlier via function `obtain_stack`. + * Released stacks MUST NOT be used anymore. + * + * Note: The implementation of this function does not make any assumptions + * about the allocation method of stack elements, but MUST match the implementation + * of function `obtain_stack` as its inverse function. + * + * @param p_stack The pointer to the stack to release. The value of the pointer + * is set to 0, if the stack was successfully released, otherwise it is left untouched. + */ +IntStack stack_release(IntStack* p_stack) { + if (p_stack == 0 || *p_stack == 0) { + return 0; + } + + IntStack stack = *p_stack; + list_release(&stack->list); + free_mem(stack); + *p_stack = 0; + + return stack; +} + +/** + * Determines whether or not the given stack is valid. + * + * @param stack The stack to evaluate. + * @return `True` if the stack is valid, false otherwise. + */ +bool stack_is_valid(IntStack stack) { + return stack != 0 && stack->list != 0; +} + +/** + * Determines whether or not the stack contains at least one item. + * + * @param stack The stack to evaluate. + * @return `False` if the stack contains one or more items, `true` otherwise. + */ +bool stack_is_empty(IntStack stack) { + return !stack_is_valid(stack) || list_is_empty(stack->list); +} + +/** + * Provides the number of values stored in the stack. + * + * @param stack The stack to evaluate. + * @return The number of values the stack contains. + */ +int stack_get_size(IntStack stack) { + if (!stack_is_valid(stack)) { + return 0; + } + + return list_get_size(stack->list); +} + +/** + * Clears the given stack by removing all values from the stack. + * + * @param stack The stack to clear. + */ +void stack_clear(IntStack stack) { + if (!stack_is_valid(stack)) { + return; + } + + list_clear(stack->list); +} + +/** + * Inserts the given value to the stack. + * + * @param stack The stack to which the value shall be appended. + * @param value The value to append to the stack. + */ +void stack_push(IntStack stack, int value) { + if (!stack_is_valid(stack)) { + return; + } + + list_insert(stack->list, value); +} + +/** + * Provides the value that 'pop' would provided but WITHOUT removing + * this value from the stack. + * + * @param stack The stack from which the value shall be peeked. + * @return The next value or 0, if the stack is empty. + */ +int stack_peek(IntStack stack) { + if (!stack_is_valid(stack)) { + return 0; + } + + return list_get_at(stack->list, stack_get_size(stack) - 1); +} + +/** + * Provides AND removes the top-most value from the stack. + * + * @param stack The stack from which the value be removed shall be returned. + * @return The value or 0, if the stack is empty. + */ +int stack_pop(IntStack stack) { + if (!stack_is_valid(stack)) { + return 0; + } + + return list_remove_at(stack->list, stack_get_size(stack) - 1); +} \ No newline at end of file diff --git a/stack.h b/stack.h index bb72705..0837804 100644 --- a/stack.h +++ b/stack.h @@ -1,9 +1,9 @@ -/*---------------------------------------------------------- + /*---------------------------------------------------------- * HTBLA-Leonding / Class: * --------------------------------------------------------- * Exercise Number: S03 * Title: Stack Inteface - * Author: */;/* + * Author: Marc Tismonar * ---------------------------------------------------------- * Description: * The declaration of a stack abstract data type. @@ -11,6 +11,7 @@ */ /** The type of the integer stack: IntStack */ +typedef struct IntStackData* IntStack; /** * Obtains ('creates') and provides a 'new' stack instance. @@ -22,7 +23,7 @@ * * @return IntStack The stack instance or 0, if no stack could by instantiated. */ - stack_obtain(); +IntStack stack_obtain(); /** * Releases a stack that was obtained earlier via function `obtain_stack`. @@ -35,7 +36,7 @@ * @param p_stack The pointer to the stack to release. The value of the pointer * is set to 0, if the stack was successfully released, otherwise it is left untouched. */ - stack_release(); +IntStack stack_release(IntStack* p_stack); /** * Determines whether or not the given stack is valid. @@ -43,7 +44,7 @@ * @param stack The stack to evaluate. * @return `True` if the stack is valid, false otherwise. */ - stack_is_valid(); +bool stack_is_valid(IntStack stack); /** * Determines whether or not the stack contains at least one item. @@ -51,7 +52,7 @@ * @param stack The stack to evaluate. * @return `False` if the stack contains one or more items, `true` otherwise. */ - stack_is_empty(); +bool stack_is_empty(IntStack stack); /** * Provides the number of values stored in the stack. @@ -59,14 +60,14 @@ * @param stack The stack to evaluate. * @return The number of values the stack contains. */ - stack_get_size(); +int stack_get_size(IntStack stack); /** * Clears the given stack by removing all values from the stack. * * @param stack The stack to clear. */ - stack_clear(); +void stack_clear(IntStack stack); /** * Inserts the given value to the stack. @@ -74,7 +75,7 @@ * @param stack The stack to which the value shall be appended. * @param value The value to append to the stack. */ - stack_push(); +void stack_push(IntStack stack, int value); /** * Provides the value that 'pop' would provided but WITHOUT removing @@ -83,7 +84,7 @@ * @param stack The stack from which the value shall be peeked. * @return The next value or 0, if the stack is empty. */ - stack_peek(); +int stack_peek(IntStack stack); /** * Provides AND removes the top-most value from the stack. @@ -91,5 +92,5 @@ * @param stack The stack from which the value be removed shall be returned. * @return The value or 0, if the stack is empty. */ - stack_pop(); +int stack_pop(IntStack stack);