/** * @file single_linked_list.c * @author libra * @date 2016年2月24日 * @version 初稿 */ #include <stdlib.h> #include <string.h> #include "single_linked_list.h" /** *@brief: list_init *@details: Initializes the linked list specified by list. This operation must be called for a linked list before the list can be used with any other operation. * Thedestroyargument provides a way to free dynamically allocated data when list_destroy is called. For example, if the list contains data dynamically allocated * usingmalloc, destroyshould be set to free to free the data as the linked list is destroyed. For structured data containing several dynamically allocated members, * destroyshould be set to a user-defined function that callsfree for each dynamically allocated member as well as for the structure itself. * For a linked list containing data that should not be freed, destroyshould be set to NULL. *@param[in][out] List *list *@param[in] void (*destroy)(void *data) *@retval: None */ void list_init(List *list, void (*destroy)(void *data)) { /*Initialize the list.*/ list->size = 0; list->destroy = destroy; list->head = NULL; list->tail = NULL; return; } /** *@brief: list_destroy *@details: Destroys the linked list specified bylist. No other operations are permitted after calling list_destroy unless list_init is called again. * The list_destroyoperation removes all elements from a linked list and calls the function passed asdestroyto list_init once for each element as it is removed, * provided destroywas not set to NULL. *@param[in][out] List *list *@retval: None */ void list_destroy(List *list) { void *data; /*Remove each element.*/ while (list_size(list) > 0) { if (list_rem_next(list, NULL, (void **)&data) == 0 && list->destroy != NULL) { /*Call a user-defined function to free dynamically allocated data.*/ list->destroy(data); } } /*No operations are allowed now, but clear the structure as a precaution.*/ memset(list, 0, sizeof(List)); return; } /** *@brief: list_ins_next *@details: Inserts an element just after elementin the linked list specified bylist.Ifelementis NULL, the new element is inserted at the head of the list. * The new element contains a pointer todata, so the memory referenced by data should remain valid as long as the element remains in the list. * It is the responsibility of the caller to manage the storage associated with data. *@param[in][out] List *list *@param[in][out] ListElmt *element *@param[in] const void *data *@retval: 0 if inserting the element is successful, or –1 otherwise. */ int list_ins_next(List *list, ListElmt *element, const void *data) { ListElmt *new_element; /*Allocate storage for the element.*/ if ((new_element = (ListElmt *)malloc(sizeof(ListElmt))) == NULL) { return -1; } /*Insert the element into the list.*/ new_element->data = (void *)data; if (element == NULL) { /*Handle insertion at the head of the list.*/ if (list_size(list) == 0) { list->tail = new_element; } new_element->next = list->head; list->head = new_element; } else { /* Handle insertion somewhere other than at the head. */ if (element->next == NULL) { list->tail = new_element; } new_element->next = element->next; element->next = new_element; } /*Adjust the size of the list to account for the inserted element.*/ list->size++; return 0; } /** *@brief: list_rem_next *@details: Removes the element just afterelementfrom the linked list specified by list.Ifelementis NULL, the element at the head of the list is removed. * Upon return,datapoints to the data stored in the element that was removed. It is * the responsibility of the caller to manage the storage associated with the data. *@param[in][out] List *list *@param[in][out] ListElmt *element *@param[out] void **data *@retval: 0 if removing the element is successful, or –1 otherwise. */ int list_rem_next(List *list, ListElmt *element, void **data) { ListElmt *old_element; /*Do not allow removal from an empty list.*/ if (list_size(list) == 0) { return -1; } /* Remove the element from the list.*/ if (element == NULL) { /*Handle removal from the head of the list.*/ *data = list->head->data; old_element = list->head; list->head = list->head->next; if (list_size(list) == 1) { list->tail = NULL; } } else { /*Handle removal from somewhere other than the head.*/ if (element->next == NULL) { return -1; } *data = element->next->data; old_element = element->next; element->next = element->next->next; if (element->next == NULL) { list->tail = element; } } /*Free the storage allocated by the abstract data type. */ free(old_element); /*Adjust the size of the list to account for the removed element.*/ list->size--; return 0; }
/** * @file single_linked_list.h * @author libra * @date 2016年2月24日 * @version 初稿 * @par 版权所有 (C), 2013-2023, 天道酬勤 * @par History: * 1.日 期: 2016年2月24日 * 作 者: libra * 修改内容: 创建文件 */ #ifndef __SINGLE_LINKED_LIST_H__ #define __SINGLE_LINKED_LIST_H__ #ifdef __cplusplus #if __cplusplus extern "C"{ #endif #endif /* __cplusplus */ /* *@brief: ListElmt *@details: Define a structure for linked list elements. */ typedef struct ListElmt_ { void *data; //!< struct ListElmt_ *next; //!< } ListElmt; /* *@brief: ListElmt *@details: Define a structure for linked lists. */ typedef struct List_ { int size //!< int (*match)(const void *key1, const void *key2);//!< void (*destroy)(void *data); //!< ListElmt *head; //!< ListElmt *tail; //!< } List; /*Public Interface*/ extern void list_destroy(List *list); extern void list_init(List *list, void (*destroy)(void *data)); extern int list_ins_next(List *list, ListElmt *element, const void *data); extern int list_rem_next(List *list, ListElmt *element, void **data); #define list_size(list) ((list)->size) #define list_head(list) ((list)->head) #define list_tail(list) ((list)->tail) #define list_is_head(list, element) ((element) == (list)->head ? 1 : 0) #define list_is_tail(element) ((element)->next == NULL ? 1 : 0) #define list_data(element) ((element)->data) #define list_next(element) ((element)->next) #ifdef __cplusplus #if __cplusplus } #endif #endif /* __cplusplus */ #endif /* __SINGLE_LINKED_LIST_H__ */
#include <string.h> #include "single_linked_list.h" /** *@brief: print_list *@param[in] const List *list *@retval: None */ static void print_list(const List *list) { ListElmt *element; int *data; int i; /*Display the linked list.*/ printf("List size is %d\n", list_size(list)); i = 0; element = list_head(list); while (1) { data = list_data(element); printf("list[%03d]=%03d\n", i, *data); i++; if (list_is_tail(element)) { break; } else { element = list_next(element); } } return; } /** *@brief: main *@param[in] void *@param[out] 无 *@retval: */ int main(void) { List list; ListElmt *element; int *data; int i; /* Initialize the linked list. */ list_init(&list, free); /* Perform some linked list operations.*/ element = list_head(&list); for (i = 10; i > 0; i--) { if ((data = (int *)malloc(sizeof(int))) == NULL) { return; } *data = i; if (list_ins_next(&list, NULL, data) != 0) { return; } } print_list(&list); element = list_head(&list); for (i = 0; i < 7; i++) { element = list_next(element); } data = list_data(element); printf("Removing an element after the one containing %03d\n", *data); if (list_rem_next(&list, element, (void **)&data) != 0) { return; } print_list(&list); printf("Inserting 011 at the tail of the list\n"); *data = 11; if (list_ins_next(&list, list_tail(&list), data) != 0) { return; } print_list(&list); printf("Removing an element after the first element\n"); element = list_head(&list); if (list_rem_next(&list, element, (void **)&data) != 0) { return; } print_list(&list); printf("Inserting 012 at the head of the list\n"); *data = 12; if (list_ins_next(&list, NULL, data) != 0) { return; } print_list(&list); printf("Iterating and removing the fourth element\n"); element = list_head(&list); element = list_next(element); element = list_next(element); if (list_rem_next(&list, element, (void **)&data) != 0) { return; } print_list(&list); printf("Inserting 013 after the first element\n"); *data = 13; if (list_ins_next(&list, list_head(&list), data) != 0) { return; } print_list(&list); i = list_is_head(&list, list_head(&list)); printf( "Testing list_is_head...Value=%d (1=OK)\n", i); i = list_is_head(&list, list_tail(&list)); printf( "Testing list_is_head...Value=%d (0=OK)\n", i); i = list_is_tail(list_tail(&list)); printf( "Testing list_is_tail...Value=%d (1=OK)\n", i); i = list_is_tail(list_head(&list)); printf( "Testing list_is_tail...Value=%d (0=OK)\n", i); /*Destroy the linked list.*/ printf("Destroying the list\n"); list_destroy(&list); }