C语言单向链表代码示例(含详细注释)

C语言单向链表代码示例

node.c

#include "node.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "student.h"
node_t *node_creat()
{
    node_t *head = malloc(sizeof(node_t));
    if (head == NULL)
    {
        return NULL;
    }
    head->data = NULL;
    head->next = NULL;
    return head;
}
int node_inser_head(node_t *head,const void * data,int size)
{
    if (head == NULL || head->data != NULL || data == NULL || size <= 0)
    {
        return -1;
    }
    node_t *temp_head = head;
    //建立新节点
    node_t *temp_node_new = malloc(sizeof(node_t)); //申请一块新的空间用来存放该节点的两个地址:*next和*data
    if (temp_node_new == NULL)
    {
        printf("空间申请失败!\n");
        return -1;
    }
    temp_node_new->data = malloc(size); //再申请一块新的空间用来存放数据,返回地址存放在该新节点的*data中
    if (temp_node_new->data == NULL)
    {
        free(temp_node_new); //如果数据域申请失败,则释放新节点的地址空间
        return -1;
    }
    //写入数据
    memcpy(temp_node_new->data, data, size);
    //链接
    temp_node_new->next=temp_head->next;
    temp_head->next=temp_node_new;
    return 0;
}

int node_inser_end(node_t *head, const void *data, int size)
{
    if (head == NULL || head->data != NULL || data == NULL || size <= 0)
    {
        return -1;
    }
    node_t *temp_head = head;
    while (temp_head->next != NULL) //找出尾部节点
    {
        temp_head = temp_head->next;
    }
    //建立新节点
    node_t *temp_node_new = malloc(sizeof(node_t)); //申请一块新的空间用来存放该节点的两个地址:*next和*data
    if (temp_node_new == NULL)
    {
        printf("空间申请失败!\n");
        return -1;
    }
    temp_node_new->data = malloc(size); //再申请一块新的空间用来存放数据,返回地址存放在该新节点的*data中
    if (temp_node_new->data == NULL)
    {
        free(temp_node_new); //如果数据域申请失败,则释放新节点的地址空间
        return -1;
    }
    //写入数据
    memcpy(temp_node_new->data, data, size);
    //链接
    temp_head->next = temp_node_new;
    temp_node_new->next = NULL;
    return 0;
}
int node_inser_node(node_t *node,const void * data,int size)
{
    if (node == NULL || data == NULL || size <= 0)
    {
        return -1;
    }
    node_t *temp_node = node;
    //建立新节点
    node_t *temp_node_new = malloc(sizeof(node_t)); //申请一块新的空间用来存放该节点的两个地址:*next和*data
    if (temp_node_new == NULL)
    {
        printf("空间申请失败!\n");
        return -1;
    }
    temp_node_new->data = malloc(size); //再申请一块新的空间用来存放数据,返回地址存放在该新节点的*data中
    if (temp_node_new->data == NULL)
    {
        free(temp_node_new); //如果数据域申请失败,则释放新节点的地址空间
        return -1;
    }
    //写入数据
    memcpy(temp_node_new->data, data, size);
    //链接
    temp_node_new->next=temp_node->next;
    temp_node->next=temp_node_new;
    return 0;
}
void node_foreach(node_t *head, void (*Show)(void *))
{
    if (head == NULL)
    {
        return;
    }
    node_t *temp_head = head;
    while (temp_head != NULL) //遍历直到尾节点
    {
        if (temp_head->data != NULL) //判断数据域是否为空值
        {
            Show(temp_head->data);
        }
        temp_head = temp_head->next; //递进一个节点
    }
}

void node_free(node_t **head)
{
    node_t *temp_head = *head;
    node_t *temp_next = NULL;
    while (temp_head != NULL) //遍历节点
    {
        temp_next = temp_head->next; //备份
        if (temp_head->data != NULL)
        {
            free(temp_head->data); //释放数据域空间
            free(temp_head);       //释放节点地址空间
        }
        temp_head = temp_next; //获取下个节点的地址
    }
    free(*head);
    *head = NULL;
}

node_t *node_find(node_t *head, const void *data, int mode, int (*cmp)(const void *, const void *, int))
{
    if (head == NULL || head->data != NULL || data == NULL || mode <= 0)
    {
        return NULL;
    }
    node_t *temp_head = head; //备份
    while (temp_head != NULL) //遍历节点
    {
        if (temp_head->data != NULL)
        {
            if (cmp(temp_head->data, data, mode) == 0) //如果找到了
            {
                return temp_head; //返回目标节点
            }
        }

        temp_head = temp_head->next;
    }
    return NULL; //没找到返回NULL节点
}

int node_updata(node_t *node, const void *data, int mode, int (*updata)(void *, const void *, const int))
{
    if (node == NULL || data == NULL || node->data == NULL || mode <= 0)
    {
        return -1;
    }
    node_t *temp_node = node;
    if (updata(temp_node->data, data, mode) == 0)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

int node_delete(node_t *head, node_t *node)
{
    if (node == NULL || head->data != NULL || head->next == NULL)
    {
        return -1;
    }
    node_t *temp_head = head;
    while (temp_head != node) //从头节点开始找node
    {
        if (temp_head->next == node) //如果该节点的下一个节点是目标节点
        {
            temp_head->next = node->next; //链接
            free(node->data);             //释放数据域
            free(node);                   //释放指针域
            return 0;
        }
        temp_head = temp_head->next; //递进
    }

    return 1;
}

node.h

#ifndef NODE_H
#define NODE_H

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


/*************
 * 函数名:node_creat
 * 功能:创建一个头节点
 * 参数:无
 * 返回值:头节点地址
 * **********/
node_t *node_creat();
/*************
 * 函数名:node_inser_end
 * 功能:尾插一组结构体数据(即在链表尾部插入)
 * 参数:
 *      head:头节点地址
 *      data:需要插入的数据
 *      size:数据大小
 * 返回值:成功返回0,失败返回非0
 * **********/
int node_inser_end(node_t *head,const void * data,int size);
/*************
 * 函数名:node_inser_head
 * 功能:头插一组结构体数据(即在head后的一个节点处插入)
 * 参数:
 *      head:头节点地址
 *      data:需要插入的数据
 *      size:数据大小
 * 返回值:成功返回0,失败返回非0
 * **********/
int node_inser_head(node_t *head,const void * data,int size);
/*************
 * 函数名:node_inser_node
 * 功能:任意节点插入一组结构体数据
 * 参数:
 *      node:节点地址
 *      data:需要插入的数据
 *      size:数据大小
 * 返回值:成功返回0,失败返回非0
 * **********/
int node_inser_node(node_t *node,const void * data,int size);
/*************
 * 函数名:node_foreach
 * 功能:遍历链表
 * 参数:
 *      head:头节点地址
 *      void(*Show)(void *):链表显示回调函数
 * 返回值:无
 * **********/
void node_foreach(node_t *head,void(*Show)(void *));
/*************
 * 函数名:node_free
 * 功能:清空该链表并释放所有的内存空间
 * 参数:
 *      head:头节点的地址&head
 * 返回值:无
 * **********/
void node_free(node_t **head);
/*************
 * 函数名:node_free
 * 功能:找到目标节点的地址
 * 参数:
 *      head:头节点的地址&head
 *      data:索引值
 *      mode:索引模式
 *      cmp:索引回调函数
 * 返回值:目标节点的地址
 * **********/
node_t *node_find(node_t *head,const void *data,int mode,int (*cmp)(const void *,const void *,int));
/*************
 * 函数名:node_updata
 * 功能:改变链表中某一个节点的某个数据元素
 * 参数:
 *      node:目标节点地址
 *      data:修改的数据源
 *      mode:更新模式
 *      updata:数据更新的回调函数
 * 返回值:成功返回0,失败返回非0
 * **********/
int node_updata(node_t *node,const void *data,int mode,int (*updata)(void *,const void *,const int));
/*************
 * 函数名:node_delete
 * 功能:删除目标节点
 * 参数:
 *      head:头节点地址
 *      node:目标节点地址
 * 返回值:成功返回0,失败返回非0
 * **********/
int node_delete( node_t *head,node_t *node);

#endif

student.c

#include "student.h"
#include <stdio.h>
#include <string.h>
void student_Print(void *data)
{
    student_t *v = data;
    printf("姓名:%s\t年龄:%d\t身高:%d\t\n", v->name, v->age, v->high);
}

int student_Cmp(const void *data_1, const void *data_2, const int mode)
{
    const student_t *v = data_1;
    const int *num2 = data_2;
    switch (mode)
    {
    case 1: //比较姓名
        return strcmp(v->name, data_2);
    case 2: //比较年龄
        return (*v).age - (*num2);
    case 3: //比较身高
        return (*v).high - (*num2);
    case 4: //比较全部
        return memcmp(v, data_2, sizeof(student_t));
    default:
        return -1;
    }
}

int student_Updata(void *data_1, const void *data_2, const int mode)
{
    student_t *v = data_1;
    const int *num2 = data_2;
    switch (mode)
    {
    case 1: //修改姓名
        strcpy(v->name,data_2);
        return 0;
    case 2: //修改年龄
        v->age = *num2;
        return 0;
    case 3: //修改身高
        v->high = *num2;
        return 0;
    case 4: //修改全部
        memcpy(v, data_2, sizeof(student_t));
        return 0;
    default:
        return -1;
    }
}

student.h

#ifndef STUDENT_H
#define STUDENT_H

typedef struct Student
{
    char name[20];
    int age;
    int high;
} student_t;
/*******************
 * 函数名:student_Print
 * 功能:学生链表打印
 * 参数:链表数据域
 * 返回值:无
 * **************/
void student_Print(void *data);
/*******************
 * 函数名:student_Cmp
 * 功能:学生信息比较
 * 参数:
 *      data_1:待比较的数据域
 *      data_2:目标数据
 *      mode:索引模式
 * 返回值:一样返回0,不一样返回非0
 * **************/
int student_Cmp(const void *data_1, const void *data_2, const int mode);
/*******************
 * 函数名:student_Updata
 * 功能:学生信息更新
 * 参数:
 *      data_1:待更新的数据域
 *      data_2:目标数据
 *      mode:更新模式
 * 返回值:成功返回0,失败返回非0
 * **************/
int student_Updata(void *data_1,const void *data_2,const int mode);

#endif

main.c

#include <stdio.h>
#include "node.h"
#include "student.h"
#include <string.h>
int main()
{
    node_t *head = node_creat(); //创建头节点
    student_t stu[6];
    strcpy(stu[0].name, "张三丰");
    stu[0].age = 100;
    stu[0].high = 200;
    strcpy(stu[1].name, "张四丰");
    stu[1].age = 101;
    stu[1].high = 201;
    strcpy(stu[2].name, "张五丰");
    stu[2].age = 102;
    stu[2].high = 202;
    strcpy(stu[3].name, "张六丰");
    stu[3].age = 103;
    stu[3].high = 203;
    strcpy(stu[4].name, "张七丰");
    stu[4].age = 104;
    stu[4].high = 204;
    node_inser_end(head, &stu[0], sizeof(student_t));  //尾插
    node_inser_head(head, &stu[1], sizeof(student_t)); //头插
    node_inser_end(head, &stu[2], sizeof(student_t));  //尾插
    node_inser_head(head, &stu[3], sizeof(student_t)); //头插
    node_inser_end(head, &stu[4], sizeof(student_t));  //尾插//理论顺序为6->4->3->5->7
    printf("---------------------------------\n");
    node_foreach(head, student_Print);
    printf("---------------------------------\n");
    char findname[] = "张五丰";
    const int findage = 104;
    const int findhigh = 204;
    node_t *findnode = node_find(head, findname, 1, student_Cmp);
    if (findnode != NULL)
    {
        student_t *v = findnode->data;
        printf("找到了!\n");
        printf("姓名:%s\t年龄:%d\t身高:%d\t\n", v->name, v->age, v->high);
        char newname[] = "张八丰";
        const int newage = 110;
        const int newhigh = 210;
        const student_t w = {"张八丰", 110, 210};
        int temp;
        temp = node_updata(findnode, newname, 1, student_Updata);
        if (temp == 0)
        {
            printf("修改成功!\n");
        }
        else
        {
            printf("修改失败! \n");
        }
    }
    else
    {
        printf("没找到\n");
    }
    printf("---------------------------------\n");
    node_foreach(head, student_Print);
    printf("---------------------------------\n");
    if (node_delete(head, findnode) == 0)
    {
        printf("删除成功!\n");
    }
    else
    {
        printf("删除失败!\n");
    }
    printf("---------------------------------\n");
    node_foreach(head, student_Print);
    printf("---------------------------------\n");
    strcpy(findname, "张三丰");
    findnode = node_find(head, findname, 1, student_Cmp); //在张三丰节点后面插入张九丰
    strcpy(stu[5].name, "张九丰");
    stu[5].age = 800;
    stu[5].high = 300;
    if (node_inser_node(findnode, &stu[5], sizeof(student_t)) == 0)
    {
        printf("插入成功!\n");
    }
    else
    {
        printf("插入失败!\n");
    }
    printf("---------------------------------\n");
    node_foreach(head, student_Print);
    printf("---------------------------------\n");
    node_free(&head); //释放链表空间
    if (head == NULL)
    {
        printf("释放成功!\n");
    }
    else
    {
        printf("释放失败!\n");
    }
    return 0;
}

运行结果

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值