如何实现C语言通用链表

    技术2025-06-21  15

    C语言通用链表实现

    C语言的数组有时候很好用,但在不知道数据有多少的时候,并且涉及到某个数据的删除时,操作起来很不方便,这个时候就需要用到链表。自己定义一个链表数据结构,然后实现它,此时这个链表仅能表示你要处理的相关数据,并不是通用的,这将导致你要使用的时候就得重新写数据结构的代码。这个时候,定义一个通用链表,用这个链表就能处理所有的数据类型了,因为是通用的,所以会有一部分代码需要在用户使用的时候自己完成。

    常见链表定义

    struct Student { char name[20]; int id; }; typedef struct node_t Node; struct node_t { struct Student stu; Node *next; };

    链表只是一个抽象概念,这里定义Node节点就可以表示一个链表信息。

    也可以在定义的标准一点:

    typedef struct { Node *head; Node *tail; size_t size; } List;

    这里定义的List就是一个完完全全的链表了,有头结点,尾节点,还有链表大小。当然还可以在这里面增加很多内容,比如定义双向链表等。但是这个链表只能处理学生信息,不具备通用性。

    下面定义一个通用链表:

    typedef struct { void *data; Node *next; } Node; typedef struct { Node *head; Node *tail; size_t size; } List;

    通过void *通用指针,我们可以处理不同的数据类型。(要是C语言可以用类型参数就好了)

    通过这个通用链表,我们可以处理任何类型的链表。不在受到数据类型的约束。但是这会引入一个问题,就是关于data部分的内容,只能交给用户来进行处理 ,因为我们在写这个代码的时候并不清楚用户要使用何种类型的数据,只有在用户使用的时候才知道用什么数据。

    所以链表该怎么写还是怎么写,当需要对data部分进行处理的时候,通过一个函数指针,把这部分的内容交给用户处理。这样,抽象出来的链表就是通用的,我们完成通用的部分,不通用的部分交给用户,用户在使用时,自己进行处理。这样能极大的减少代码量,还是能很方便的使用的。

    list.h,list.c是我们定义的通用链表内容。用户使用的时候定义list_custom.h和list_custom.c,在这里完成data的定义和处理。

    下面展示代码:

    list.h

    #ifndef __LIST_H__ #define __LIST_H__ #include <stdio.h> typedef void (* p_free)(void *data); typedef void *(* p_malloc)(size_t size); typedef int (* p_traverse)(void *nodeData, void *data); typedef struct note_t Node; struct note_t{ void *data; Node *next; }; typedef struct { Node * head; Node * tail; int size; } List; List * init_list(void); int delete_list(List *plist, p_free pfun_free); Node * create_node(void *data, p_malloc pfun_malloc, size_t size); int delete_node(Node *pnode, p_free pfun_free); int add_node(List *plist, Node *pnode); int remove_node(List *plist, p_free pfun_free); int remove_node_by_data(List *plist, void *data, p_traverse pfun_compare, p_free pfun_free); int traverse_list(List *plist, void *data, p_traverse p_fun); Node * get_node_by_index(List *plist, int index); Node * find_node_by_data(List *plist, void *data, p_traverse pfun_compare); int get_index_by_data(List *plist, void *data, p_traverse pfun_compare); void sort_list(List *plist); #endif /* __LIST_H__ */

    list.c

    #include "list.h" #include <stdlib.h> #include <string.h> #include "sal.h" List * init_list(void) { List *plist = NULL; plist = (List *)malloc(sizeof(List)); if (NULL == plist) { return NULL; } plist->head = NULL; plist->tail = NULL; plist->size = 0; return plist; } Node * create_node(void *data, p_malloc pfun_malloc, size_t size) { if (NULL == data) { return NULL; } Node *pnode = NULL; pnode = (Node *)malloc(sizeof(Node)); if (NULL == pnode) { return NULL; } pnode->data = pfun_malloc(size); if (pnode->data == NULL) { free(pnode); return NULL; } memcpy(pnode->data, data, size); pnode->next = NULL; return pnode; } int delete_node(Node *pnode, p_free pfun_free) { SAL_CHECK_P_NULL(pnode); pfun_free(pnode->data); free(pnode); return SAL_OK; } int delete_list(List *plist, p_free pfun_free) { SAL_CHECK_P_NULL(plist); Node *pnode = plist->head; for (; pnode != NULL; pnode = plist->head) { plist->head = plist->head->next; delete_node(pnode, pfun_free); } free(plist); return SAL_OK; } int add_node(List *plist, Node *pnode) { SAL_CHECK_P_NULL(pnode); SAL_CHECK_P_NULL(plist); if (NULL == plist->head) { plist->head = pnode; plist->tail = pnode; } else { plist->tail->next = pnode; plist->tail = pnode; } plist->size++; return SAL_OK; } Node * get_node_by_index(List *plist, int index) { if (NULL == plist || NULL == plist->head || index < 1 || index > plist->size) { return NULL; } Node *pnode = plist->head; for (int i = 1; i < index; i++) { pnode = pnode->next; } return pnode; } int remove_node(List *plist, p_free pfun_free) { SAL_CHECK_P_NULL(plist); if (plist->size == 1) { delete_node(plist->tail, pfun_free); plist->head = NULL; plist->tail = NULL; } else { Node *pnode = get_node_by_index(plist, plist->size - 1); if (NULL == pnode) { return SAL_ERR; } delete_node(plist->tail, pfun_free); plist->tail = pnode; plist->tail->next = NULL; } plist->size--; return SAL_OK; } int remove_node_by_data(List *plist, void *data, p_traverse pfun_compare, p_free pfun_free) { SAL_CHECK_P_NULL(plist); SAL_CHECK_P_NULL(data); if (plist->size == 1 && 0 == pfun_compare(plist->head->data, data)) { remove_node(plist, pfun_free); } else { Node *pnode = plist->head; for (Node *pprior = NULL; pnode != NULL; pprior = pnode, pnode = pnode->next) { if (0 == pfun_compare(pnode->data, data)) { pprior->next = pnode->next; if (pnode == plist->tail) { plist->tail = pprior; } delete_node(pnode, pfun_free); plist->size--; } } } return SAL_OK; } int get_index_by_data(List *plist, void *data, p_traverse pfun_compare) { SAL_CHECK_P_NULL(plist); SAL_CHECK_P_NULL(data); Node *pnode = plist->head; for (int index = 1; pnode != NULL; index++, pnode = pnode->next) { if (0 == pfun_compare(pnode->data, data)) { return index; } } return 0; } Node * find_node_by_data(List *plist, void *data, p_traverse pfun_compare) { if (NULL == plist || NULL == data) { return NULL; } #if 0 int index = get_index_by_data(plist, data); if (index > 0) { Node *pnode = NULL; pnode = get_node_by_index(plist, index); if (pnode != NULL) { return pnode; } } #else Node *pnode = plist->head; for (; pnode != NULL; pnode = pnode->next) { if (0 == pfun_compare(pnode->data, data)) { return pnode; } } #endif return NULL; } int traverse_list(List *plist, void *data, p_traverse pfun_traverse) { SAL_CHECK_P_NULL(plist); Node *pnode = plist->head; for (; pnode != NULL; pnode = pnode->next) { pfun_traverse(pnode->data, data); } return SAL_OK; }

    main.c

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include "list.h" #include "list_custom.h" int main() { List *students; /* 初始化一个空链表 */ students = init_list(); struct Student std[5] = { {"李明", 2001}, {"王强", 2002}, {"徐晓丽", 2003}, {"张强", 2004}, {"李伟", 2005} }; /* 将结构体数据装载到链表中 */ for (int i = 0; i < 5; i++) { Node *student = create_node(std + i, student_malloc, sizeof(struct Student)); add_node(students, student); } /* 遍历链表,打印学生信息 */ printf("\r\n------学生排名成绩表-------\r\n"); traverse_list(students, NULL, student_print); printf("-------------------------\r\n\r\n"); /* 假设链表的顺序是按照成绩排名的,取得第3名的学生信息 */ Node *pnode = get_node_by_index(students, 3); struct Student * stu3 = (struct Student *)(pnode->data); printf("第三名同学信息 name : %s, id : %d\r\n", stu3->name, stu3->id); /* 找到名字叫张强的学生信息 */ pnode = find_node_by_data(students, "张强", stu_name_compare); if (NULL == pnode) { printf("查无此人(张强)\r\n"); } else { struct Student * stu = (struct Student *)(pnode->data); printf("张强 name : %s, id : %d\r\n", stu->name, stu->id); } /* 假设链表的顺序是按照成绩排名的,取得李明同学的名次 */ int rank = get_index_by_data(students, "李明", stu_name_compare); if (rank < 1) { printf("李明未上榜\r\n"); } else { printf("李明的排名: %d\r\n", rank); } /* 王强同学考试作弊,踢出成绩排名表单 */ remove_node_by_data(students, "王强", stu_name_compare, student_free); printf("\r\n------学生排名成绩表-------\r\n"); traverse_list(students, NULL, student_print); printf("-------------------------\r\n\r\n"); delete_list(students, student_free); /* 初始化工人信息链表 */ List *worker = init_list(); return 0; }

    list_custom.h

    #ifndef __LIST_CUSTOM_H__ #define __LIST_CUSTOM_H__ #include <stdio.h> /* 在这里定义自己的链表Data内容 */ struct Student { char name[20]; int id; }; /* eg: 员工薪酬Data */ struct Worker { char name[20]; //姓名 long payment; //薪酬 char tele[12]; //电话 }; /* 学生信息表自定义处理HANDLE */ void *student_malloc(size_t size); int student_print(void *nodeData, void *data); int stu_name_compare(void *nodeData, void *data); void student_free(void *data); /* 在这里定义Data处理Handle,eg: Worker*/ #endif /* __LIST_CUSTOM_H__ */

    list_custom.c

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include "list.h" #include "list_custom.h" void *student_malloc(size_t size) { struct student *stu = (struct student *)malloc(size); return stu; } int student_print(void *nodeData, void *data) { struct Student *stu = (struct Student *)(nodeData); printf("%s %d\r\n", stu->name, stu->id); } int stu_name_compare(void *nodeData, void *data) { char * name1 = (char *)nodeData; char * name2 = (char *)data; if (0 == strcmp(name1, name2)) { return 0; } return -1; } void student_free(void *data) { struct Student *stu = (struct Student *)data; free(stu); }

    链表测试结果

    river@SHIELD-HJ:/mnt/f/Code/Code/clist$ ./test ------学生排名成绩表------- 李明 2001 王强 2002 徐晓丽 2003 张强 2004 李伟 2005 ------------------------- 第三名同学信息 name : 徐晓丽, id : 2003 张强 name : 张强, id : 2004 李明的排名: 1 ------学生排名成绩表------- 李明 2001 徐晓丽 2003 张强 2004 李伟 2005 -------------------------

    要实现remove_node_by_index可以先用get_node_by_index然后再remove_node_by_data。

    github连接:https://github.com/duapple/Code/tree/master/clist

    Processed: 0.011, SQL: 9