左丘雅秀 发表于 2025-6-27 15:12:12

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

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

}
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 单向链表的初始化、插入、删除、遍历