自定义单链表(非循环)的基本接口函数

文件描述及头文件包含

/*******************************************************************
 *
 *	文件名称  :	单链表(非循环)的基本接口程序
 *	文件作者  : mailLinL@163.com
 *	创建日期  :  2024/05/07
 *	文件功能  :  对单链表的增删改查功能的定义
 *	注意事项  :  None
 *
 *	CopyRight (c)  2024   mailLinL@163.com   All Right Reseverd
 *
 * *****************************************************************/
#include <stdlib.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>

定义数据类型,构造链表结点结构体

// 指的是单向链表中的结点有效数据类型,用户可以根据需要进行修改
typedef int DataType_t;

// 构造链表的结点,链表中所有结点的数据类型应该是相同的
typedef struct LinkedList
{
    DataType_t data;         // 结点的数据域
    struct LinkedList *next; // 结点的指针域

} LList_t;

创建链表

/*******************************************************************
 *
 *	函数名称:	LList_Create
 *	函数功能:   创建一个空链表,空链表应该有一个头结点,对链表进行初始化
 *	函数参数:
 *	返回结果:
 *			    @Head	返回创建成功后的头结点地址
 *	注意事项:   None
 *	函数作者:   mailLinL@163.com
 *	创建日期:   2024/05/06
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/

// 创建一个空链表,空链表应该有一个头结点,对链表进行初始化
LList_t *LList_Create(void)
{
    // 1.创建一个头结点并对头结点申请内存
    LList_t *Head = (LList_t *)calloc(1, sizeof(LList_t));
    if (NULL == Head)
    {
        perror("Calloc memory for Head is Failed");
        exit(-1);
    }

    // 2.对头结点进行初始化,头结点是不存储有效内容的!!!
    Head->next = NULL;

    // 3.把头结点的地址返回即可
    return Head;
}

新结点创建

/*******************************************************************
 *
 *	函数名称:	LList_NewNode
 *	函数功能:   创建新的结点,并对新结点进行初始化(数据域 + 指针域)
 *	函数参数:
 *              @data       传入需要新建结点数据域的值
 *	返回结果:
 *			    @New	返回创建成功后的新结点地址
 *	注意事项:   None
 *	函数作者:   mailLinL@163.com
 *	创建日期:   2024/05/06
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
// 创建新的结点,并对新结点进行初始化(数据域 + 指针域)
LList_t *LList_NewNode(DataType_t data)
{
    // 1.创建一个新结点并对新结点申请内存
    LList_t *New = (LList_t *)calloc(1, sizeof(LList_t));
    if (NULL == New)
    {
        perror("Calloc memory for NewNode is Failed");
        return NULL;
    }
    // 2.对新结点的数据域和指针域进行初始化
    New->data = data;
    New->next = NULL;
    return New;
}

头插法插入新结点

/*******************************************************************
 *
 *	函数名称:	LList_HeadInsert
 *	函数功能:   向链表的头部插入新结点
 *	函数参数:
 *              @Head   传入需要操作的链表的头结点
 *              @data   传入需要插入的数据
 *	返回结果:
 *			    @bool	返回插入是否成功
 *	注意事项:   None
 *	函数作者:   mailLinL@163.com
 *	创建日期:   2024/05/06
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
// 头插
bool LList_HeadInsert(LList_t *Head, DataType_t data)
{
    // 1.创建新的结点,并对新结点进行初始化
    LList_t *New = LList_NewNode(data);
    if (NULL == New)
    {
        printf("can not insert new node\n");
        return false;
    }

    // 2.判断链表是否为空,如果为空,则直接插入即可
    if (NULL == Head->next)
    {
        Head->next = New;
        return true;
    }

    // 3.如果链表为非空,则把新结点插入到链表的头部
    New->next = Head->next;
    Head->next = New;

    return true;
}

尾插法插入新结点

/*******************************************************************
 *
 *	函数名称:	LList_TailInsert
 *	函数功能:   向链表的尾部插入新结点
 *	函数参数:
 *              @Head   传入需要操作的链表头结点地址
 *              @data   传入需要插入的结点的数据域的值
 *	返回结果:
 *			    @bool	返回插入是否成功
 *	注意事项:   None
 *	函数作者:   mailLinL@163.com
 *	创建日期:   2024/05/06
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
bool LList_TailInsert(LList_t *Head, DataType_t data)
{
    // 1.创建新的结点,并对新结点进行初始化
    LList_t *New = LList_NewNode(data);
    if (NULL == New)
    {
        printf("can not insert new node\n");
        return false;
    }

    // 2.判断链表是否为空,如果为空,则直接插入即可
    if (NULL == Head->next)
    {
        Head->next = New;
        return true;
    }

    // 3.如果非空,向后遍历到尾结点进行插入操作
    else
    {
        // 对链表的头文件的地址进行备份
        LList_t *Phead = Head;
        while (Phead->next)
        {
            Phead = Phead->next;
        }
        Phead->next = New;
    }
    return true;
}

目标结点后插入新结点

/*******************************************************************
 *
 *	函数名称:	LList_DestInsert
 *	函数功能:   向链表的指定节点后插入新结点
 *  函数参数:
 *              @Head   传入需要操作的链表头结点地址
 *              @dest   传入目标结点的数据域的值
 *              @data   传入需要插入的结点的数据域的值
 *	返回结果:
 *			    @bool	返回插入是否成功
 *	注意事项:   None
 *	函数作者:   mailLinL@163.com
 *	创建日期:   2024/05/06
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
bool LList_DestInsert(LList_t *Head, DataType_t dest, DataType_t data)
{
    // 1.对链表的头文件的地址进行备份
    LList_t *Phead = Head;
    // 2.判断链表中是否有目标结点
    while (Phead->next)
    {
        // 当存在目标结点时  停止循环
        if (Phead->data == dest)
        {
            break;
        }
        else
        {
            Phead = Phead->next;
        }
    }
    // 3.判断是否因为找到目标结点而停止循环
    if (Phead->next == NULL && Phead->data != dest)
    {
        return false;
    }

    // 4.向该结点后插入新结点 创建新的结点,并对新结点进行初始化
    LList_t *New = LList_NewNode(data);
    New->next = Phead->next;
    Phead->next = New;
    return true;
}

头删法删除结点

/*******************************************************************
 *
 *	函数名称:	LList_HeadDel
 *	函数功能:   删除首结点
 *  函数参数:
 *              @Head   传入需要操作的链表头结点地址
 *	返回结果:
 *	注意事项:   None
 *	函数作者:   mailLinL@163.com
 *	创建日期:   2024/05/06
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
bool LList_HeadDel(LList_t *Head)
{
    // 1.判断链表是否为空
    if (Head->next == NULL)
    {
        return false;
    }
    else
    {
        // 2.对链表的首结点的地址进行备份
        LList_t *Phead = Head->next;
        // 3.删除首结点
        Head->next = Phead->next; // 将头结点指向首结点的下一个结点
        Phead->next = NULL;       // 将原首结点的next指针指向NULL
        free(Phead);              // 释放原首结点的空间
        return true;
    }
}

尾删法删除结点

/*******************************************************************
 *
 *	函数名称:	LList_HeadDel
 *	函数功能:   删除尾结点
 *  函数参数:
 *              @Head   传入需要操作的链表头结点地址
 *	返回结果:
 *	注意事项:   None
 *	函数作者:   mailLinL@163.com
 *	创建日期:   2024/05/06
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
bool LList_TailDel(LList_t *Head)
{
    // 1.判断链表是否为空
    if (Head->next == NULL)
    {
        return false;
    }
    else
    {
        // 2.对链表的首结点及头结点的地址进行备份
        LList_t *temp = Head;
        LList_t *Phead = Head->next;
        // 3.遍历查找尾结点地址
        while (Phead->next)
        {
            temp = temp->next;
            Phead = Phead->next;
        }
        // 4.删除尾结点
        temp->next = NULL;
        free(Phead);
        return true;
    }
}

删除指定节点

/*******************************************************************
 *
 *	函数名称:	LList_DestDel
 *	函数功能:   删除指定结点
 *  函数参数:
 *              @Head   传入需要操作的链表头结点地址
 *              @dest   传入需要删除的目标结点
 *	返回结果:
 *	注意事项:   None
 *	函数作者:   mailLinL@163.com
 *	创建日期:   2024/05/06
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
bool LList_DestDel(LList_t *Head, DataType_t dest)
{
    // 1.判断链表是否为空
    if (Head->next == NULL)
    {
        return false;
    }
    else
    {
        // 2.对链表的首结点及头结点的地址进行备份
        LList_t *temp = Head;
        LList_t *Phead = Head->next;
        // 3.遍历链表寻找目标结点
        while (Phead)
        {
            if (Phead->data == dest) // 当前结点数据域的值与目标值相同时 跳出循环
            {
                break;
            }
            temp = temp->next; // 不同时  指针向后继续遍历
            Phead = Phead->next;
        }
        // 4.判断是否因为找到尾结点而结束
        if (Phead->next == NULL && Phead->data != dest)
        {
            return false;
        }
        else
        {
            temp->next = Phead->next; // 将目标结点直接前驱的next指针指向目标结点直接后继的地址
            Phead->next = NULL;       // 将目标节点的next指针指向NULL
            free(Phead);              // 释放目标结点的内存
            return true;
        }
    }
}

遍历打印所有结点

/*******************************************************************
 *
 *	函数名称:	LList_Print
 *	函数功能:   遍历打印所有结点
 *  函数参数:
 *              @Head   传入需要操作的链表头结点地址
 *	返回结果:
 *	注意事项:   None
 *	函数作者:   mailLinL@163.com
 *	创建日期:   2024/05/06
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
// 遍历
void LList_Print(LList_t *Head)
{
    // 对链表的头文件的地址进行备份
    LList_t *Phead = Head;

    // 首结点
    while (Phead->next)
    {
        // 把头的直接后继作为新的头结点
        Phead = Phead->next;

        // 输出头结点的直接后继的数据域
        printf("data = %d\n", Phead->data);
    }
}

测试主函数

/*******************************************************************
 *
 *	函数名称:	main
 *	函数功能:   主函数  用于测试自定义函数功能是否正确
 *  函数参数:
 *	返回结果:
 *	注意事项:   None
 *	函数作者:   mailLinL@163.com
 *	创建日期:   2024/05/06
 *	修改历史:
 *	函数版本:	V1.0
 * *****************************************************************/
int main()
{
    // 新建空链表
    LList_t *head = LList_Create();
    // 尾插法插入数据10  15
    LList_TailInsert(head, 10);
    LList_TailInsert(head, 15);
    LList_Print(head);
    printf("\n");
    // 头插法插入数据30  25  20  10  15
    LList_HeadInsert(head, 20);
    LList_HeadInsert(head, 25);
    LList_HeadInsert(head, 30);
    LList_Print(head);
    printf("\n");
    // 指定目标后插入数据30  25  20  5  10  15
    LList_DestInsert(head, 20, 5);
    LList_Print(head);
    printf("\n");
    // 头删25  20  5  10  15
    LList_HeadDel(head);
    LList_Print(head);
    printf("\n");
    // 尾删25  20  5  10
    LList_TailDel(head);
    LList_Print(head);
    printf("\n");
    // 指定删除目标结点25  5  10
    LList_DestDel(head, 20);
    LList_Print(head);
    printf("\n");
    return 0;
}

测试结果

image

posted @   林大官人995  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示