From 0c8b8b251d642c1a22bf4eda8d2214d680b67faf Mon Sep 17 00:00:00 2001 From: William Brawner Date: Mon, 18 Nov 2024 17:55:01 -0700 Subject: [PATCH] Add find and delete operations for doubly-linked list --- include/doubly-linked-list.h | 13 ++++++++++++- src/doubly-linked-list.c | 33 +++++++++++++++++++++++++++++++++ test/dll.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/include/doubly-linked-list.h b/include/doubly-linked-list.h index c26204c..325a94f 100644 --- a/include/doubly-linked-list.h +++ b/include/doubly-linked-list.h @@ -6,6 +6,7 @@ struct dll_node { typedef struct dll_node dll_node; +// TODO: I probably don't need a separate "list" type typedef struct { struct dll_node *head; } dll_list; @@ -33,7 +34,17 @@ void dll_list_append(dll_list *list, dll_node *node) { dll_list_insert(list, node, -1); } -// TODO: find and delete operations on list +/** + * Searches the given list for a node with a given value + * @returns a pointer to the node with the value or NULL if no nodes match the value + */ +dll_node *dll_list_find(dll_list *list, char *value); + +/** + * Removes the first node with the matching value in the given list + * @returns a pointer to the node with the value or NULL if no nodes match the value + */ +dll_node *dll_list_delete(dll_list *list, char *value); dll_node *dll_node_new(char *value); diff --git a/src/doubly-linked-list.c b/src/doubly-linked-list.c index 691e25f..4177f50 100644 --- a/src/doubly-linked-list.c +++ b/src/doubly-linked-list.c @@ -50,6 +50,39 @@ void dll_list_insert(dll_list *list, dll_node *node, int index) { current_node->next = node; } +dll_node *dll_list_find(dll_list *list, char *value) { + if (list == NULL) { + return NULL; + } + + dll_node *current_node = list->head; + while (current_node != NULL) { + if (strcmp(current_node->value, value) == 0) { + return current_node; + } + current_node = current_node->next; + } + + return NULL; +} + +dll_node *dll_list_delete(dll_list *list, char *value) { + dll_node *target_node = dll_list_find(list, value); + if (target_node == NULL) { + return NULL; + } + + if (target_node->previous != NULL) { + target_node->previous->next = target_node->next; + } else { + list->head = target_node->next; + } + if (target_node->next != NULL) { + target_node->next->previous = target_node->previous; + } + return target_node; +} + dll_node *dll_node_new(char *value) { dll_node *node = malloc(sizeof(dll_node)); node->previous = NULL; diff --git a/test/dll.c b/test/dll.c index 64f4aa7..1f862e5 100644 --- a/test/dll.c +++ b/test/dll.c @@ -8,6 +8,17 @@ dll_list *list = NULL; dll_node *head = NULL; char *list_string = NULL; +#define ASSERT_PTR_EQ(expected, actual) \ + { \ + if (expected != actual) { \ + fprintf(stderr, \ + "pointers don't match. expected: \"%p\", actual: \"%p\"\n", \ + (void*)expected, (void*)actual); \ + cleanup(); \ + return 1; \ + } \ + } + #define ASSERT_STR_EQ(expected, actual) \ { \ if (strcmp(expected, actual) != 0) { \ @@ -71,6 +82,7 @@ int main(int argc, char **argv) { dll_list_append(list, head); head = NULL; // TODO: Extract test utilities to shared file + // TODO: Maybe break these out into separate files? list_string = list_to_string(list); ASSERT_STR_EQ("0", list_string); @@ -88,6 +100,23 @@ int main(int argc, char **argv) { list_string = list_to_string(list); ASSERT_STR_EQ("0, 1, 2", list_string); + ASSERT_PTR_EQ(second, dll_list_find(list, "1")); + + ASSERT_PTR_EQ(third, dll_list_delete(list, "2")); + dll_node_free(third); + + free(list_string); + list_string = list_to_string(list); + ASSERT_STR_EQ("0, 1", list_string); + + head = list->head; + ASSERT_PTR_EQ(head, dll_list_delete(list, "0")); + dll_node_free(head); + + free(list_string); + list_string = list_to_string(list); + ASSERT_STR_EQ("1", list_string); + cleanup(); return 0; }