diff --git a/DataStructures/link_list/link_list.c b/DataStructures/link_list/link_list.c new file mode 100644 index 0000000..075a675 --- /dev/null +++ b/DataStructures/link_list/link_list.c @@ -0,0 +1,365 @@ +#include "link_list.h" + +/** + * @brief Creates a new instance of a `list_t`. + * @return a pointer to the created list. + */ +list_t* list_create() +{ + list_t* list; + + list = malloc(sizeof(*list)); + list->size = 0; + list->head = NULL; + list->tail = NULL; + return (list); +} + +/** + * @brief Same as `list_create` except no dynamic + * allocation on the heap will be perform to create + * the list. + * @return a list_t value + */ +list_t list_create_static() +{ + return ((list_t) { + .size = 0, + .head = NULL, + .tail = NULL + }); +} + +/** + * @brief Clears the list by deleting every node in it. + * The list will still be usable after this call. + */ +void list_clear(list_t* list) +{ + node_t* node = list->head; + + while (!list_is_empty(list)) { + node_t* next = node->next; + + list_remove_node(list, node); + node = next; + } +} + +/** + * @brief Destroys every element of the given `list` and + * frees the memory allocated by the `list`. The given pointer + * will not be usable after a call to this function. + */ +void list_destroy(list_t* list) +{ + list_clear(list); + free(list); +} + +/** + * @brief Allows to iterate over each node held by the list by pushing + * each of them to the given `iterator`. + */ +void list_iterate_over_nodes(const list_t* list, list_predicate_t iterator, void* data) +{ + node_t* node = list->head; + + for (size_t i = 0; i < list->size; ++i) { + if (iterator(i, node, data) < 0) { + break; + } + node = node->next; + } +} + +/** + * @brief Searches the list for the given `node`. + * @return the found node if any, NULL otherwise. + */ +node_t* list_find_node(const list_t* list, const node_t* element) +{ + node_t* node = list->head; + + for (size_t i = 0; i < list->size; ++i) { + if (node == element) { + return (node); + } + node = node->next; + } + return (NULL); +} + +/** + * @brief Finds an element using the return value of the given `predicate`. + * @return the node matching the given predicate. + */ +node_t* list_find_node_if(const list_t* list, list_predicate_t iterator, void* data) +{ + node_t* node = list->head; + + for (size_t i = 0; i < list->size; ++i) { + if (iterator(i, node, data)) { + return (node); + } + node = node->next; + } + return (NULL); +} + +/** + * @return the size of the given `list`. That is, the number of nodes currently + * held by the list. + */ +size_t list_get_size(const list_t* list) +{ + return (list->size); +} + +/** + * @return a positive value if the given `list` is + * empty, zero otherwise. + */ +int list_is_empty(const list_t* list) +{ + return (list_get_size(list) == 0); +} + +/** + * @brief Creates a new node instance initialized + * with the given `element`. + * @return a new instance of a `node_t`. + */ +node_t* node_new(void* element) +{ + node_t* node; + + node = malloc(sizeof(*node)); + node->element = element; + node->next = NULL; + node->prev = NULL; + return (node); +} + +/** + * @brief Adds a new element to the `list`. This will cause a new `node_t` + * to be created, holding the given `element` and pushed at the front of the + * given `list`. + * @return a pointer to the newly created node. + */ +node_t* list_push_front(list_t* list, void* element) +{ + node_t* node = node_new(element); + node_t* head = list->head; + + if (head) { + // Binding the node to the list elements. + node->next = head; + node->prev = head->prev; + // Binding the list elements to the node. + head->prev->next = node; + head->prev = node; + } else { + node->next = node; + node->prev = node; + list->tail = node; + } + list->head = node; + list->size++; + return (node); +} + +/** + * @brief Adds a new element to the `list`. This will cause a new `node_t` + * to be created, holding the given `element` and pushed to the back of the + * given `list`. + * @return a pointer to the newly created node. + */ +node_t* list_push_back(list_t* list, void* element) +{ + node_t* node = node_new(element); + node_t* tail = list->tail; + + if (tail) { + // Binding the node to the list elements. + node->next = tail->next; + node->prev = tail; + // Binding the list elements to the node. + tail->next->prev = node; + tail->next = node; + } else { + node->next = node; + node->prev = node; + list->head = node; + } + list->tail = node; + list->size++; + return (node); +} + +/** + * @brief Removes the node associated with the given node pointer + * from the list. + * @return the pointer held by the removed node. + */ +void* list_pop_node(list_t* list, node_t* node) +{ + void* element; + + if (!node) { + return (NULL); + } + element = node->element; + list_remove_node(list, node); + return (element); +} + +/** + * @brief Removes the node located at the head of the list. + * @return the pointer held by the removed node. + */ +void* list_pop_back(list_t* list) +{ + return (list_pop_node(list, list->tail)); +} + +/** + * @brief Removes the node located at the tail of the list. + * @return the pointer held by the removed node. + */ +void* list_pop_front(list_t* list) +{ + return (list_pop_node(list, list->head)); +} + +/** + * @return a new instance of an iterator. The iterator's current node + * will be `node` if the given pointer is non-NULL, or the head of the + * given `list` otherwise. + */ +list_iterator_t list_make_iterator(list_t* list, node_t* node) +{ + return ((list_iterator_t) { + .current = (node != NULL ? node : list->head != NULL ? + list->head->prev : NULL), + .list = list + }); +} + +/** + * @return whether it is possible to go forward in the list. + */ +int list_iterator_has_next(const list_iterator_t* it) +{ + return (it->current != NULL && it->current->next != NULL); +} + +/** + * @return whether it is possible to go backward in the list. + */ +int list_iterator_has_prev(const list_iterator_t* it) +{ + return (it->current != NULL && it->current->prev != NULL); +} + +/** + * @brief Removes the current node from the list. + * @return a positive value if the removal succeeded, + * zero otherwise. + */ +int list_iterator_remove(list_iterator_t* it) +{ + node_t* current = it->current; + + if (!current) + return (0); + if (current == current->next) + it->current = NULL; + else + it->current = current->next; + return (list_remove_node(it->list, current)); +} + +/** + * @brief Moves the iterator's current node pointer forward. If + * it is not possible to do so, the function will not modify the + * iterator's current node pointer. + * @return the current node if moving forward succeeded, + * NULL otherwise. + */ +node_t* list_iterator_next(list_iterator_t* it) +{ + if (!list_iterator_has_next(it)) { + return (NULL); + } + return (it->current = it->current->next); +} + +/** + * @brief Moves the iterator's current node pointer backward. If + * it is not possible to do so, the function will not modify the + * iterator's current node pointer. + * @return the current node if moving backward succeeded, + * NULL otherwise. + */ +node_t* list_iterator_prev(list_iterator_t* it) +{ + if (!list_iterator_has_prev(it)) { + return (NULL); + } + return (it->current = it->current->prev); +} + +/** + * @brief Removes the given `node` from the `list` + * and frees the memory allocated by the `node`. + * @return a positive value if the given `node` has + * been successfully removed from the `list`, a negative + * value otherwise. + */ +int list_remove_node(list_t* list, node_t* node) +{ + node_t* found = list_find_node(list, node); + + if (found != NULL) { + found->prev->next = found->next; + found->next->prev = found->prev; + if (list->head == found) { + list->head = found->next; + } + if (list->tail == found) { + list->tail = found->prev; + } + list->size--; + if (list->size == 0) { + list->tail = NULL; + list->head = NULL; + } + free(found); + return (1); + } + return (0); +} + +/** + * @brief Conditionally removes a node from the list based on the return + * value of the given `predicate`. + * @return the number of removed nodes. + */ +int list_remove_node_if(list_t* list, list_predicate_t iterator, void* data) +{ + node_t* node = list->head; + int removed = 0; + + for (size_t i = 0; i < list->size; ++i) { + node_t* next = node->next; + + if (iterator(i, node, data)) { + list_remove_node(list, node); + removed++; + i -= 1; + } + node = next; + } + return (removed); +} diff --git a/DataStructures/link_list/link_list.h b/DataStructures/link_list/link_list.h new file mode 100644 index 0000000..d3b8e12 --- /dev/null +++ b/DataStructures/link_list/link_list.h @@ -0,0 +1,218 @@ +#ifndef CIRCULAR_LINKED_LIST +#define CIRCULAR_LINKED_LIST + +#ifdef __cplusplus +extern "C" { +#endif + +#include + + /** + * @brief A node holds a pointer to the user-defined + * element required to be stored, a pointer to + * the next element in the list, and a pointer to + * the previous element in the list. + */ + typedef struct node_t + { + void* element; + struct node_t* next; + struct node_t* prev; + } node_t; + + /** + * @brief Definition of the circular doubly linked-list. + * It holds informations about the current size + * of the list, a pointer to the head node of the list, + * and a pointer to the tail of the list. + */ + typedef struct list_t + { + size_t size; + struct node_t* head; + struct node_t* tail; + } list_t; + + /** + * @brief The list iterator structure allows + * to memorize a pointer to a `node_t`. It also holds + * a pointer to the list the node belongs to. + * The `data` pointer is reserved for future usage. + * @see list_make_iterator + */ + typedef struct list_iterator_t + { + list_t* list; + node_t* current; + void* data; + } list_iterator_t; + + /** + * @brief A predicate type to be used when iterating over + * each node of the list. + * @see list_iterate_over_nodes + */ + typedef int (*list_predicate_t)(size_t index, node_t* node, void* data); + + /** + * @brief Creates a new instance of a `list_t`. + * @return a pointer to the created list. + */ + list_t* list_create(); + + /** + * @brief Same as `list_create` except no dynamic + * allocation on the heap will be perform to create + * the list. + * @return a list_t value + */ + list_t list_create_static(); + + /** + * @brief Clears the list by deleting every node in it. + * The list will still be usable after this call. + */ + void list_clear(list_t* list); + + /** + * @brief Destroys every element of the given `list` and + * frees the memory allocated by the `list`. The given pointer + * will not be usable after a call to this function. + */ + void list_destroy(list_t* list); + + /** + * @brief Adds a new element to the `list`. This will cause a new `node_t` + * to be created, holding the given `element` and pushed at the front of the + * given `list`. + * @return a pointer to the newly created node. + */ + node_t* list_push_front(list_t* list, void* element); + + /** + * @brief Adds a new element to the `list`. This will cause a new `node_t` + * to be created, holding the given `element` and pushed to the back of the + * given `list`. + * @return a pointer to the newly created node. + */ + node_t* list_push_back(list_t* list, void* element); + + /** + * @brief Allows to iterate over each node held by the list by pushing + * each of them to the given `iterator`. + */ + void list_iterate_over_nodes(const list_t* list, list_predicate_t iterator, void* data); + + /** + * @brief Searches the list for the given `node`. + * @return the found node if any, NULL otherwise. + */ + node_t* list_find_node(const list_t* list, const node_t* node); + + /** + * @brief Finds an element using the return value of the given `predicate`. + * @return the node matching the given predicate. + */ + node_t* list_find_node_if(const list_t* list, list_predicate_t iterator, void* data); + + /** + * @brief Removes the given `node` from the `list` + * and frees the memory allocated by the `node`. + * @return a positive value if the given `node` has + * been successfully removed from the `list`, a negative + * value otherwise. + */ + int list_remove_node(list_t* list, node_t* node); + + /** + * @brief Conditionally removes a node from the list based on the return + * value of the given `predicate`. + * @return the number of removed nodes. + */ + int list_remove_node_if(list_t* list, list_predicate_t predicate, void* data); + + /** + * @return the size of the given `list`. That is, the number of nodes currently + * held by the list. + */ + size_t list_get_size(const list_t* list); + + /** + * @return a positive value if the given `list` is + * empty, zero otherwise. + */ + int list_is_empty(const list_t* list); + + /** + * @brief Removes the node associated with the given node pointer + * from the list. + * @return the pointer held by the removed node. + */ + void* list_pop_node(list_t* list, node_t* node); + + /** + * @brief Removes the node located at the head of the list. + * @return the pointer held by the removed node. + */ + void* list_pop_back(list_t* list); + + /** + * @brief Removes the node located at the tail of the list. + * @return the pointer held by the removed node. + */ + void* list_pop_front(list_t* list); + + /** + * @return a new instance of an iterator. The iterator's current node + * will be `node` if the given pointer is non-NULL, or the head of the + * given `list` otherwise. + */ + list_iterator_t list_make_iterator(list_t* list, node_t* node); + + /** + * @return whether it is possible to go forward in the list. + */ + int list_iterator_has_next(const list_iterator_t* it); + + /** + * @return whether it is possible to go backward in the list. + */ + int list_iterator_has_prev(const list_iterator_t* it); + + /** + * @brief Moves the iterator's current node pointer forward. If + * it is not possible to do so, the function will not modify the + * iterator's current node pointer. + * @return the current node if moving forward succeeded, + * NULL otherwise. + */ + node_t* list_iterator_next(list_iterator_t* it); + + /** + * @brief Moves the iterator's current node pointer backward. If + * it is not possible to do so, the function will not modify the + * iterator's current node pointer. + * @return the current node if moving backward succeeded, + * NULL otherwise. + */ + node_t* list_iterator_prev(list_iterator_t* it); + + /** + * @brief Removes the current node from the list. + * @return a positive value if the removal succeeded, + * zero otherwise. + */ + int list_iterator_remove(list_iterator_t* it); + + /** + * @brief Creates a new node instance initialized + * with the given `element`. + * @return a new instance of a `node_t`. + */ + node_t* node_new(void* element); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/DataStructures/link_list/simple.c b/DataStructures/link_list/simple.c new file mode 100644 index 0000000..d92d7e7 --- /dev/null +++ b/DataStructures/link_list/simple.c @@ -0,0 +1,108 @@ +#include +#include +#include "link_list.h" + + +typedef enum Sex{ + male = 0, + female, + other +}Sex_TypeDef; + +typedef struct Student{ + + int no; + Sex_TypeDef sex; + +}Student_TypeDef; + + +void create_student(list_t *l){ + + int x; + + Student_TypeDef* s; + + s = malloc(sizeof(Student_TypeDef)); + + if (s == NULL){ + printf("\nbad malloc "); + return; + } + + printf("\nEnter student number: "); + scanf(" %d", &x); + s->no = x; + printf("\nEnter student sex(0:male 1:female 2:other): "); + scanf(" %d", &x); + s->sex = (Sex_TypeDef)x; + + list_push_front(l, s); +} + + +int find_student(size_t index, node_t *node, void* data){ + + Student_TypeDef *n = (Student_TypeDef *)node->element; + Student_TypeDef *d = (Student_TypeDef *)data; + + if(n->no == d->no) + return 1; + else + return 0; +} + +void delete_student(list_t *l){ + + int x; + Student_TypeDef* s; + + s = malloc(sizeof(Student_TypeDef)); + + if (s == NULL){ + printf("\nbad malloc "); + return; + } + + printf("\nEnter student number: "); + scanf(" %d", &x); + s->no = x; + + int a = list_remove_node_if(l, find_student, s); + printf("\n%d node deleted!", a); + +} + +int print_student(size_t index, node_t *node, void* data){ + + Student_TypeDef *s = (Student_TypeDef*)node->element; + printf("\nno: %d", (int)index); + printf("\n>>>Student Number: %d", s->no); + printf("\n>>>Enter student sex: %d ", s->sex); +} +void display_student(list_t *l){ + + void *data; + list_iterate_over_nodes(l, print_student, data); +} +void main() +{ + printf("< - Link List - Creation - Deletion - Traversal - >\n"); + int ch; + list_t *l; + l = list_create(); + while(1){ + printf("\n*********************************"); + printf("\n1. create/insert() \n2. display()\n3. delete()\n4.exit()\n Choice: "); + scanf(" %d", &ch); + + switch(ch){ + + case 1: create_student(l); break; + case 2: display_student(l); break; + case 3: delete_student(l); break; + case 4: exit(1); break; + default: printf("\nwrong input!");break; + } + } +}