From 7fa3e5e626318e34dc61c9f258e34e3760324745 Mon Sep 17 00:00:00 2001
From: Mactavish <maczhanchao@yahoo.com>
Date: Mon, 1 May 2023 09:27:41 +0200
Subject: [PATCH] add solution to linked-list

---
 exercises/linked-list/linked_list.c | 139 +++++++++++++++++++++++++---
 1 file changed, 127 insertions(+), 12 deletions(-)

diff --git a/exercises/linked-list/linked_list.c b/exercises/linked-list/linked_list.c
index 8981740..054dc38 100644
--- a/exercises/linked-list/linked_list.c
+++ b/exercises/linked-list/linked_list.c
@@ -1,55 +1,170 @@
 #include "linked_list.h"
+#include <errno.h>
+#include <stdlib.h>
+
+#define FAULT(ERRNO, ERR_CODE)                                                 \
+  errno = ERRNO;                                                               \
+  exit(ERR_CODE);
+
+#define FREE_NODE(NODE)                                                        \
+  if (NODE) {                                                                  \
+    free(NODE);                                                                \
+    NODE = NULL;                                                               \
+  }
+
 
 struct list_node {
-   struct list_node *prev, *next;
-   ll_data_t data;
+  struct list_node *prev, *next;
+  ll_data_t data;
 };
 
 struct list {
-   struct list_node *first, *last;
+  struct list_node *first, *last;
 };
 
 struct list_node *create_node(ll_data_t data) {
-    // TODO: implement create_node
+  struct list_node *node;
+  node = malloc(sizeof(struct list_node));
+  if (!node) {
+    FAULT(ENOMEM, EXIT_FAILURE);
+  }
+  node->data = data;
+  return node;
 }
 
 // constructs a new (empty) list
 struct list *list_create(void) {
-    // TODO: implement list_create
+  struct list *head = malloc(sizeof(struct list));
+  // create a dummy node, dummy node should not have any previous node
+  struct list_node *node = create_node(0);
+  head->first = node;
+  head->last = node;
+  node->prev = node->next = NULL;
+  return head;
 }
 
 // counts the items on a list
 size_t list_count(const struct list *list) {
-    // TODO: implement list_count
+  size_t count = 0;
+  if (list->first == list->last) {
+    return count;
+  }
+  struct list_node *dummy = list->first;
+  struct list_node *node = dummy->next;
+  while (node != dummy) {
+    node = node->next;
+    count++;
+  }
+  return count;
 }
 
 // inserts item at back of a list
 void list_push(struct list *list, ll_data_t item_data) {
-    // TODO: implement list_push
+  struct list_node *node = create_node(item_data);
+  // empty list with a dummy node
+  if (list->first == list->last) {
+    list->first->next = node;
+    list->last = node;
+    node->prev = node->next = list->first;
+  } else {
+    node->prev = list->last;
+    list->last->next = node;
+    node->next = list->first;
+    list->last = node;
+  }
 }
 
 // removes item from back of a list
 ll_data_t list_pop(struct list *list) {
-    // TODO: implement list_pop
+  // empty list with a dummy node
+  if (list->first == list->last) {
+    FAULT(EFAULT, EXIT_FAILURE);
+  }
+  struct list_node *last = list->last;
+  ll_data_t data = last->data;
+  list->last = last->prev;
+  last->prev->next = list->first;
+  FREE_NODE(last);
+  return data;
 }
 
 // inserts item at front of a list
 void list_unshift(struct list *list, ll_data_t item_data) {
-  // TODO: implement list_unshift
+  // empty list with a dummy node
+  if (list->first == list->last) {
+    list_push(list, item_data);
+  } else {
+    struct list_node *dummy = list->first, *node = create_node(item_data);
+    node->next = dummy->next;
+    node->prev = dummy;
+    dummy->next->prev = node;
+    dummy->next = node;
+  }
 }
 
 // removes item from front of a list
 ll_data_t list_shift(struct list *list) {
-    // TODO: implement list_shift
+  // empty list with a dummy node
+  if (list->first == list->last) {
+    FAULT(EFAULT, EXIT_FAILURE);
+  } else {
+    struct list_node *dummy = list->first, *node;
+    node = dummy->next;
+    ll_data_t data = node->data;
+    dummy->next = node->next;
+    // if there are more than one nodes
+    if (node->next->prev == node) {
+      node->next->prev = dummy;
+    } else {
+      list->last = list->first;
+    }
+    FREE_NODE(node);
+    return data;
+  }
 }
 
 // deletes a node that holds the matching data
 void list_delete(struct list *list, ll_data_t data) {
-    // TODO: implement list_delete
+  if (list->first == list->last) {
+    errno = EFAULT;
+    exit(EXIT_FAILURE);
+  } else {
+    struct list_node *dummy = list->first;
+    struct list_node *node = dummy->next;
+    while (node != dummy) {
+      if (node->data == data) {
+        break;
+      }
+      node = node->next;
+    }
+    if (node != dummy) {
+      node->prev->next = node->next;
+      node->next->prev = node->prev;
+      if (node == list->last) {
+        list->last = node->prev;
+      }
+      FREE_NODE(node);
+    }
+  }
 }
 
 // destroys an entire list
 // list will be a dangling pointer after calling this method on it
 void list_destroy(struct list *list) {
-    // TODO: implement list_destroy
+  // empty list with a dummy node
+  if (list->first == list->last) {
+    FREE_NODE(list->last);
+    FREE_NODE(list);
+  } else {
+    struct list_node *dummy = list->first;
+    struct list_node *node = dummy->next, *next;
+    while (node != dummy) {
+      next = node->next;
+      FREE_NODE(node);
+      node = next;
+    }
+    FREE_NODE(dummy);
+    FREE_NODE(list);
+  }
 }
+
-- 
GitLab