如何实现C语言通用链表

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.hlist.c是我们定义的通用链表内容。用户使用的时候定义list_custom.hlist_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

高级版
list.h

#ifndef __LIST_H__
#define __LIST_H__

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdio.h>

#define CLIST_OK 0
#define CLIST_ERR 1
#define CLIST_ERR_MEM 2
#define CLIST_ERR_PTR_NULL 3
#define CLIST_ERR_OPERATION 4
#define CLIST_ERR_NULL -1

#ifndef CLIST_CHECK_PTR_NULL
#define CLIST_CHECK_PTR_NULL(p)    \
    if (!p)                        \
    {                              \
        return CLIST_ERR_PTR_NULL; \
    }
#endif

typedef struct node_t Node;
struct node_t
{
    void *data;
    Node *next;
};

typedef struct 
{
    void (*user_data_free)(void *data);                         // 用户释放数据,不包含*data的释放
    int (*node_compare)(void *node_data, void *data);           // 用户数据和节点数据比较,相等返回0
} clist_user_hooks_t;

typedef struct list_t List;
struct list_t
{
    Node *head;
    Node *tail;
    int size;

    clist_user_hooks_t user_hooks;

    /* private */
    int (*delete_node)(List *plist, Node *pnode);
    Node * (*create_node)(List *plist, void *data, size_t size);

    /* public */
    void (*clist_delete_list)(List *plist);
    int (*node_add)(List *plist, void *data, size_t size);
    int (*node_del)(List *plist);
    int (*node_del_by_data)(List *plist, void *data, int (*p_traverse)(void *node_data, void *data));
    void * (*clist_get_data_by_index)(List *plist, int index);
    void * (*clist_get_data_by_data)(List *plist, void *data, int (*p_traverse)(void *node_data, void *data));
    int (*clist_get_index_by_data)(List *plist, void *data, int (*p_traverse)(void *node_data, void *data));
    int (*clist_traverse_list)(List *plist, void *data, int (*p_traverse)(void *node_data, void *data));
};

List * clist_new_list(clist_user_hooks_t *hooks);

#ifdef __cplusplus
}
#endif

#endif /* __LIST_H__ */

list.c

#include "list.h"
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#define LIST_LOG_INFO(...) // printf(__VA_ARGS__)

int clist_delete_node(List *plist, Node *pnode)
{
    CLIST_CHECK_PTR_NULL(pnode);

    plist->user_hooks.user_data_free(pnode->data);   // 释放用户分配的数据
    free(pnode->data);                    // 释放节点数据空间
    free(pnode);                          // 释放节点
    pnode = NULL;

    return CLIST_OK;
}

Node * clist_create_node(List *plist, void *data, size_t size)
{
    if (!data)
    {
        return NULL;
    }

    Node *pnode = NULL;
    pnode = (Node *)malloc(sizeof(Node));
    if (!pnode)
    {
        return NULL;
    }
    pnode->data = malloc(size);
    if (!pnode->data)
    {
        free(pnode);
        return NULL;
    }
    memcpy(pnode->data, data, size);
    plist->user_hooks.user_data_free(data);
    pnode->next = NULL;

    return pnode;
}

void clist_delete_list(List *plist)
{
    if (plist == NULL)
        return ;

    Node *pnode = plist->head;
    for (; pnode != NULL; pnode = plist->head)
    {
        plist->head = plist->head->next;
        plist->delete_node(plist, pnode);
    }
    free(plist);
    plist = NULL;
}

int clist_node_add(List *plist, void *data, size_t size)
{
    CLIST_CHECK_PTR_NULL(data);
    CLIST_CHECK_PTR_NULL(plist);

    Node *pnode = plist->create_node(plist, data, size);
    if (pnode == NULL) {
        return CLIST_ERR_PTR_NULL;
    }

    if (NULL == plist->head)
    {
        plist->head = pnode;
        plist->tail = pnode;
    }
    else
    {
        plist->tail->next = pnode;
        plist->tail = pnode;
    }
    plist->size++;

    return CLIST_OK;
}

int clist_node_del(List *plist)
{
    CLIST_CHECK_PTR_NULL(plist);

    if (plist->size == 1)
    {
        plist->delete_node(plist, plist->tail);
        plist->head = NULL;
        plist->tail = NULL;
    }
    else
    {
        Node *pnode = plist->clist_get_data_by_index(plist, plist->size - 1);
        if (!pnode)
        {
            return CLIST_ERR_PTR_NULL;
        }
        plist->delete_node(plist, plist->tail);
        plist->tail = pnode;
        plist->tail->next = NULL;
    }
    plist->size--;

    return CLIST_OK;
}

int clist_node_del_by_data(List *plist, void *data, int (*p_traverse)(void *node_data, void *data))
{
    CLIST_CHECK_PTR_NULL(plist);
    CLIST_CHECK_PTR_NULL(data);

    if (plist->size == 1 && p_traverse(plist->head->data, data) == 0)
    {
        if (plist->node_del(plist) != CLIST_OK)
        {
            return CLIST_ERR_OPERATION;
        }
    }
    else
    {
        Node *pnode = plist->head;
        for (Node *pprior = NULL; pnode != NULL; pprior = pnode, pnode = pnode->next)
        {
            if (p_traverse(pnode->data, data) == 0)
            {
                pprior->next = pnode->next;
                if (pnode == plist->tail)
                {
                    plist->tail = pprior;
                }

                plist->delete_node(plist, pnode);
                plist->size--;
            }
        }
    }

    return CLIST_OK;
}

void * clist_get_data_by_index(List *plist, int index)
{
    if (!plist || !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->data;
}

void * clist_get_data_by_data(List *plist, void *data, int (*p_traverse)(void *node_data, void *data))
{
    if (!plist || !data)
    {
        return NULL;
    }

    Node *pnode = plist->head;
    for (; pnode != NULL; pnode = pnode->next)
    {
        if (p_traverse(pnode->data, data) == 0)
        {
            return pnode->data;
        }
    }

    return NULL;
}

int clist_get_index_by_data(List *plist, void *data, int (*p_traverse)(void *node_data, void *data))
{
    CLIST_CHECK_PTR_NULL(plist);
    CLIST_CHECK_PTR_NULL(data);

    Node *pnode = plist->head;
    for (int index = 1; pnode != NULL; index++, pnode = pnode->next)
    {
        if (p_traverse(pnode->data, data) == 0)
        {
            return index;
        }
    }

    return 0;
}

int clist_traverse_list(List *plist, void *data, int (*p_traverse)(void *node_data, void *data))
{
    CLIST_CHECK_PTR_NULL(plist);

    Node *pnode = plist->head;
    for (; pnode != NULL; pnode = pnode->next)
    {
        p_traverse(pnode->data, data);
    }

    return CLIST_OK;
}


List * clist_new_list(clist_user_hooks_t *user_hooks)
{
    if (user_hooks == NULL || user_hooks->user_data_free == NULL || user_hooks->node_compare == NULL)
        return NULL;

    List *plist = (List *)malloc(sizeof(List));
    if (plist == NULL) {
        return NULL;
    }

    plist->head = NULL;
    plist->tail = NULL;
    plist->size = 0;

    plist->user_hooks.user_data_free = user_hooks->user_data_free;
    plist->user_hooks.node_compare = user_hooks->node_compare;

    plist->create_node = clist_create_node;
    plist->delete_node = clist_delete_node;

    plist->clist_delete_list = clist_delete_list;
    plist->node_add = clist_node_add;
    plist->node_del = clist_node_del;
    plist->node_del_by_data = clist_node_del_by_data;
    plist->clist_get_data_by_data = clist_get_data_by_data;
    plist->clist_get_data_by_index = clist_get_data_by_index;
    plist->clist_get_index_by_data = clist_get_index_by_data;
    plist->clist_traverse_list = clist_traverse_list;

    return plist;
}
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值