单向链表的初始化、插入、删除、遍历

/********************************************************************
*   file name: LnList.c
*   author   :  MINDSETT@163.com
*   date     :  2025/6/24
*   function :  实现一个单向不循环链表的接口,可实现链表的增删改查,另外为了提高可移植性,所以链表中
*               数据元素的类型为DataType_t,用户可以根据实际情况修改链表中元素的类型
*   note     :  None
*
*   CopyRight (c)  2025  MINDSETT@163.com  All Right Reserved
********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

//指定链表中元素的数据类型,用户可根据需要进行修改
typedef int DataType_t;

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

/********************************************************************
*   name     :  Seqlist_Creat
*   function :  创建一个空链表,空链表应该有一个头节点,对链表进行初始化
*   argument :  None
*   retval   :  返回头结点的地址
*   author   :  MINDSETT@163.com
*   date     :  2025/6/24 
*   note     :  None
*
* ******************************************************************/
LnList_t *LnList_Create(void)
{
    //创建一个头结点并对头结点申请内存
    LnList_t* Head=(LnList_t*)calloc(1,sizeof(LnList_t));
    if (NULL==Head){
        perror("calloc memory for Head is failed\n");
        exit(-1);
    }
    //对头结点进行初始化
    Head->next=NULL;
    //将头结点的地址返回
    return Head;
}


/********************************************************************
*   name     :  LnList_NewNode
*   function :  创建一个新结点,并为新结点申请堆内存以及对新结点的数据域和指针域进行初始化
*   argument :  
*               @data:新结点的数据
*   retval   :  返回新结点的地址
*   author   :  MINDSETT@163.com
*   date     :  2025/6/24 
*   note     :  None
*
* ******************************************************************/
LnList_t * LnList_NewNode(DataType_t data)
{
    //创建新结点,并未新结点申请堆内存
    LnList_t * New=(LnList_t*)calloc(1,sizeof(LnList_t));
     if (NULL==New){
        perror("calloc memory for NewNode is failed\n");
        return NULL;
    }
    //对新结点的数据域和指针域进行初始化
    New->data=data;
    New->next=NULL;
    return New;
}

/********************************************************************
*   name     :  LnList_FirstInsert
*   function :  创建一个新结点,并把新结点插入链表的首部
*   argument :  
*               @Head:插入的链表
*               @data:新结点的数据
*   retval   :  成功返回true,失败返回false
*   author   :  MINDSETT@163.com
*   date     :  2025/6/24 
*   note     :  None
*
* ******************************************************************/
bool LnList_FirstInsert(LnList_t * Head,DataType_t data)
{
    //创建新结点,并对新结点进行初始化
    LnList_t* New=LnList_NewNode(data);
    if (NULL==New){
        perror("Create New node is failed\n");
        return false;
    }
    //判断链表是否为空,如果为空,则将新结点直接插入
    if (NULL==Head->next){
        Head->next=New;
        return true;
    }
    //如果链表为非空,则将新结点插入链表的首部
    New->next=Head->next;
    Head->next=New;

    return true;
}

/********************************************************************
*   name     :  LnList_TailInsert
*   function :  创建一个新结点,并把新结点插入链表的尾部
*   argument :  
*               @Head:插入的链表
*               @data:新结点的数据
*   retval   :  成功返回true,失败返回false
*   author   :  MINDSETT@163.com
*   date     :  2025/6/24 
*   note     :  None
*
* ******************************************************************/
bool LnList_TailInsert(LnList_t * Head,DataType_t data)
{
    //创建新结点,并对新结点进行初始化
    LnList_t* New=LnList_NewNode(data);
    if (NULL==New){
        perror("Create New node is failed\n");
        return false;
    }
    //判断链表是否为空,如果为空,则将新结点直接插入
    if (NULL==Head->next){
        Head->next=New;
        return true;
    }
    //如果链表为非空,则链表的头结点的地址进行备份,循环找到链表的尾部,并将新结点插入链表的尾部
    LnList_t *Phead=Head;
    while(Phead->next){
        Phead=Phead->next;
    }
    Phead->next=New;

    return true;
}

/********************************************************************
*   name     :  LnList_DestInsert 
*   function :  创建一个新结点,并把新结点插入链表的指定位置
*   argument :  
*               @Head:插入的链表
*               @Dest:指定需要新结点插入位置的直接前驱的数据
*               @data:新结点的数据
*   retval   :  成功返回true,失败返回false
*   author   :  MINDSETT@163.com 
*   date     :  2025/6/24 
*   note     :  None
*
* ******************************************************************/

bool LnList_DestInsert(LnList_t * Head,DataType_t Dest,DataType_t data)
{
    //创建新结点,并对新结点进行初始化
    LnList_t* New=LnList_NewNode(data);
    if (NULL==New){
        perror("Create New node is failed\n");
        return false;
    }
    //判断链表是否为空,如果为空,则将新结点直接插入
    if (NULL==Head->next){
        Head->next=New;
        return true;
    }
    //如果链表为非空,遍历链表,目的是找到目标结点,比较结点的数据域
    LnList_t *Phead=Head->next;
    while(Phead!=NULL && Dest!=Phead->data){
        Phead=Phead->next;
    }
    if(NULL==Phead){
        printf("Dest is not found\n");
        return false;
    }
    //找到目标结点,则把新结点加入到目标结点的后面
    New->next=Phead->next;
    Phead->next=New;

    return true;
}

/********************************************************************
*   name     :  LnList_FirstDel
*   function :  删除链表的首结点
*   argument :  
*               @Head:链表的头结点
*   retval   :  成功返回true,失败返回false
*   author   :  MINDSETT@163.com 
*   date     :  2025/6/24 
*   note     :  None
*
* ******************************************************************/
bool LnList_FirstDel(LnList_t* Head)
{
    //判断链表是否为空
    if (NULL==Head || NULL==Head->next){
        perror("Linked list is empty\n");
        return false;
    }
    //备份链表的头结点和首结点
    LnList_t* Pfirst=Head->next;
    //将头结点的指针域指向首结点的指针域
    Head->next=Pfirst->next;
    //释放首结点占用的内存
    Pfirst->next=NULL;
    free(Pfirst);

    return true;
}

/********************************************************************
*   name     :  LnList_TailDel
*   function :  删除链表的尾结点
*   argument :  
*               @Head:链表的头结点
*   retval   :  成功返回true,失败返回false
*   author   :  MINDSETT@163.com 
*   date     :  2025/6/24 
*   note     :  None
*
* ******************************************************************/
bool LnList_TailDel(LnList_t* Head)
{
    //判断链表是否为空
    if (NULL==Head || NULL==Head->next){
        perror("Linked list is empty\n");
        return false;
    }
    //备份链表的头结点和首结点
    LnList_t* Phead=Head;
    LnList_t* Pfirst=Phead->next;
    //循环找到链表的尾结点和尾结点的直接前驱
    while(Pfirst->next){
        Pfirst=Pfirst->next;
        Phead=Phead->next;
    }
    //将尾结点的直接前驱的指针域指向为NULL
    Phead->next=NULL;
    //释放尾结点占用的内存
    free(Pfirst);

    return true;
}

/********************************************************************
*   name     :  LnList_DestDel
*   function :  删除链表的指定结点
*   argument :  
*               @Head:链表的头结点
*               @Dest:需要删除的指定结点
*   retval   :  成功返回true,失败返回false
*   author   :  MINDSETT@163.com 
*   date     :  2025/6/24 
*   note     :  None
*
* ******************************************************************/
bool LnList_DestDel(LnList_t* Head,DataType_t Dest)
{
    //判断链表是否为空
    if (NULL==Head || NULL==Head->next){
        perror("Linked list is empty\n");
        return false;
    }
    //Phead指向前驱,Pfirst指向当前结点
    LnList_t* Phead=Head;
    LnList_t* Pfirst=Phead->next;
    //遍历链表,目的是找到目标结点,比较结点的数据域
    while(Pfirst!=NULL && Dest!=Pfirst->data){
        Phead=Pfirst;
        Pfirst=Pfirst->next;
    }
    if(NULL==Pfirst){
        printf("Dest is not found\n");
        return false;
    }
    //删除目标结点——将指定结点的直接前驱的指针域指向指定结点的直接后继
    Phead->next=Pfirst->next;
    //释放指定结点占用的内存
    Pfirst->next=NULL;
    free(Pfirst);

    return true;
}

/********************************************************************
*   name     :  LnList_Print
*   function :  遍历输出链表中各个结点的数据
*   argument :  
*               @Head:需要遍历的链表
*   retval   :  None
*   author   :  MINDSETT@163.com
*   date     :  2025/6/24 
*   note     :  None
*
* ******************************************************************/
void LnList_Print(LnList_t* Head)
{
    //判断链表是否为空
    if (NULL==Head || NULL==Head->next){
        perror("Linked list is empty\n");
        return ;
    }
    //对链表的头节点的地址进行备份
    LnList_t *Phead=Head;
    //循环遍历链表
    while(Phead->next){
        //把头结点的直接后继作为新的头结点
        Phead= Phead->next;
        //输出头结点的直接后继的数据域
        printf("Data=%d\n",Phead->data);
    }

}
posted @ 2025-06-27 15:43  verd  阅读(21)  评论(0)    收藏  举报