-->

数据结构中的单向不循环链表

单向不循环链表


  • 链表就是通过离散的内存,来存储数据,一个数据被称为结点,每一个结点有存放自己的数据以及下一个结点的地址

image

  • 链表的节点

//存储数据类型(可修改),在遍历数据的时候是需要输出的,所以输出类型也需要修改
//链表节点下面是数据的数据类型
typedef int DataType_t;

//带头结点的链表
//1.每一个节点都有自己的元素和连接下一个元素的地址
typedef struct linklist
{
    DataType_t          data;   //链表节点存放的数据
    struct linklist     *next;  //链表节点存放下一个链表节点的地址
}LkList_t;

创建链表

image

/***************************************************
*       函数名称:   LkList_CreatList
*       函数功能:   创建一个新的链表
*       函数参数:   None
*       返回结果:   返回链表的地址:创建成功。NULL:创建失败。
*       注意事项:   None
*       函数作者:
*       创建日期:   2024/04/22
*       修改历史:
*       函数版本:   V1.0
***************************************************/
LkList_t * LkList_CreatList(void)
{
    //在堆空间申请一个空间存放链表的头结点
    LkList_t * Head = (LkList_t *)calloc(1,sizeof(LkList_t));
    if(NULL == Head){
        perror("calloc memory for head is failed!!!");
        return NULL;
    }

    //头结点的初始化,数据不需要初始化
    Head->next = NULL;

    //返回头结点的地址
    return Head;
}

创建新结点

/***************************************************
*       函数名称:   LkList_NewNode
*       函数功能:   创建一个链表新的节点
*       函数参数:   
*                   @data   :创建链表节点时,下面存放的数值
*       返回结果:   返回链表的地址:创建成功。NULL:创建失败。
*       注意事项:   一般都在插入的时候需要使用,不会单独使用
*       函数作者:
*       创建日期:   2024/04/22
*       修改历史:
*       函数版本:   V1.0
***************************************************/
LkList_t * LkList_NewNode(DataType_t data)
{
    //1.先从堆空间申请内存存放链表节点
    LkList_t * New = (LkList_t *)calloc(1,sizeof(LkList_t));
    if(NULL == New){
        perror("Calloc memory for NewNode is failed!");
        return NULL;
    }

    //初始化链表节点
    New->data = data;
    New->next = NULL;
    
    //申请成功直接返回
    return New;
}

头部插入结点

image

/***************************************************
*       函数名称:   LkList_HeadInsertNode
*       函数功能:   在头节点的后面插入新的节点
*       函数参数:   
*                   @Head   :头结点的地址
*                   @data   :创建链表节点时,下面存放的数值
*       返回结果:   true:插入成功;false:插入失败
*       注意事项:   Node
*       函数作者:
*       创建日期:   2024/04/22
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool LkList_HeadInsertNode(LkList_t * Head,DataType_t data)
{
    //1.先判断链表是否存在
    if(NULL == Head){
        printf("Linklist head is not exist!!!\n");
        return false;
    }

    //创建新的节点
    LkList_t * New = LkList_NewNode(data);
    if(NULL == New){
        return false;
    }

    //如果存在,直接把头结点指向的地址赋值给新的节点下面的地址
    New->next = Head->next;
    Head->next = New;

    return true;
}

尾部插入结点

image

/***************************************************
*       函数名称:   LkList_TailInsertNode
*       函数功能:   在尾部节点的后面插入新的节点
*       函数参数:   
*                   @Head   :头结点的地址
*                   @data   :创建链表节点时,下面存放的数值
*       返回结果:   true:插入成功;false:插入失败
*       注意事项:   Node
*       函数作者:
*       创建日期:   2024/04/22
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool LkList_TailInsertNode(LkList_t * Head,DataType_t data)
{
    //1.先判断链表是否存在
    if(NULL == Head){
        printf("Linklist head is not exist!!!\n");
        return false;
    }

    //创建新的节点
    LkList_t * New = LkList_NewNode(data);
    if(NULL == New){
        return false;
    }
	
	//判断是否只有头结点
	if(Head->next == NULL){
		Head->next = New;
		return true;
	}
	
	//备份头结点对地址,以免丢失链表
    LkList_t *Phead = Head->next;

    //寻找尾部节点,判断Phead->next是否为空
    while(Phead->next){
        Phead = Phead->next;
    }

    //到了尾部节点可以开始添加
    New->next = Phead->next;
    Phead->next = New;

    return true;
}

中间插入结点

image

/***************************************************
*       函数名称:   LkList_MediumInsertNode
*       函数功能:   在源数据dest_data后面插入data数据
*       函数参数:   
*                   @Head      		:头结点的地址
*                   @dest_data   	:要寻找的链表的数据
*                   @data  			:要插入的数据
*       返回结果:   true:插入成功;false:插入失败
*       注意事项:   Node
*       函数作者:
*       创建日期:   2024/04/23
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool LkList_MediumInsertNode(LkList_t * Head,DataType_t dest_data,DataType_t data)
{
    //1.先判断链表是否存在
    if(NULL == Head){
        printf("Linklist head is not exist!!!\n");
        return false;
    }

    //创建新的节点
    LkList_t * New = LkList_NewNode(data);
    if(NULL == New){
        return false;
    }

    //备份头结点用来寻找到data结点的位置
    LkList_t *Phead = Head->next;

    //寻找到数据节点,防止死循环
    while((Phead->data != dest_data) && (Phead->next != NULL)){
        Phead = Phead->next;
    }

    //判断是不是没找到
    if((Phead->data != dest_data) && (Phead->next == NULL)){
        printf("dest_data(%d) is not found!\n",dest_data);
        return false;
    }

    //寻找到数据节点可以在后面插入,无论是在尾还是中间都可以插入
    New->next = Phead->next;
    Phead->next = New;

    return true;
}

头部删除结点

image

  • 在删除结点时,需要判断链表是否为空
/***************************************************
*       函数名称:   LkList_IsEmpty
*       函数功能:   判断链表是否为空
*       函数参数:   
*                   @Head   :头结点的地址
*       返回结果:   true:为空;false:不为空
*       注意事项:   Node
*       函数作者:
*       创建日期:   2024/04/23
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool LkList_IsEmpty(LkList_t * Head)
{
	return (Head->next == NULL) ? true : false;
}

/***************************************************
*       函数名称:   LkList_HeadDelNode
*       函数功能:   把链表的首结点删除
*       函数参数:   
*                   @Head   :头结点的地址
*       返回结果:   true:删除成功;false:删除失败
*       注意事项:   Node
*       函数作者:
*       创建日期:   2024/04/23
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool LkList_HeadDelNode(LkList_t * Head)
{
    //1.先判断链表是否存在
    if(NULL == Head){
        printf("Linklist head is not exist!!!\n");
        return false;
    }
	
	//判断链表是否为空
	if(LkList_IsEmpty(Head)){
		printf("Linklist is empty!!!\n");
		return false;
	}
	
    //定义变量存储当前结点直接让他指向首节点的地址,以便于释放删除的结点
    LkList_t *Phead = Head->next;

    //寻找到数据节点可以开始删除
	Head->next = Phead->next;
	Phead->next = NULL;
    free(Phead);
    Phead = NULL;

    return true;
}

尾部删除结点

image

/***************************************************
*       函数名称:   LkList_TailDelNode
*       函数功能:   把链表的首结点删除
*       函数参数:   
*                   @Head   :头结点的地址
*       返回结果:   true:删除成功;false:删除失败
*       注意事项:   Node
*       函数作者:
*       创建日期:   2024/04/23
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool LkList_TailDelNode(LkList_t * Head)
{
    //1.先判断链表是否存在
    if(NULL == Head){
        printf("Linklist head is not exist!!!\n");
        return false;
    }
	
	//判断链表是否为空
	if(LkList_IsEmpty(Head)){
		printf("Linklist is empty!!!\n");
		return false;
	}
	
    //定义变量存储当前结点以及当前结点的直接前驱
    LkList_t *Phead = Head->next;
    LkList_t *Phead_prev = Head;

    //寻找到尾结点,以及尾结点的直接前驱
    while(Phead->next){
        Phead = Phead->next;
        Phead_prev = Phead_prev->next;
    }

    //寻找到数据节点可以开始删除
    Phead_prev->next = NULL;
    free(Phead);
    Phead = NULL;

    return true;
}

中间删除结点

image

/***************************************************
*       函数名称:   LkList_MediumDelNode
*       函数功能:   把这个数据节点删除
*       函数参数:   
*                   @Head   :头结点的地址
*                   @data   :要删除的数据节点
*       返回结果:   true:删除成功;false:删除失败
*       注意事项:   Node
*       函数作者:
*       创建日期:   2024/04/23
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool LkList_MediumDelNode(LkList_t * Head,DataType_t data)
{
    //1.先判断链表是否存在
    if(NULL == Head){
        printf("Linklist head is not exist!!!\n");
        return false;
    }
	
	//判断链表是否为空
	if(LkList_IsEmpty(Head)){
		printf("Linklist is empty!!!\n");
		return false;
	}
	
    //定义变量存储当前结点和当前结点的直接前驱
    LkList_t *Phead = Head->next;
    LkList_t *Phead_prev = Head;

    //寻找到数据节点,并且防止没有这个数据
    while((Phead->data != data) && (Phead->next)){
        Phead = Phead->next;
        Phead_prev = Phead_prev->next;
    }
	
	//判断数据是否存在
	if((Phead->data != data) && (Phead->next == NULL)){
		printf("data(%d) is not exist!!!\n",data);
        return false;
	}
    
    //寻找到数据节点可以开始删除
    Phead_prev->next = Phead->next;
    Phead->next = NULL;
    free(Phead);
    Phead = NULL;

    return true;
}

遍历链表

/***************************************************
*       函数名称:   LkList_TraNode
*       函数功能:   遍历输出每一个结点的数据
*       函数参数:   
*                   @Head   :头结点的地址
*       返回结果:   true:遍历成功;false:遍历失败
*       注意事项:   Node
*       函数作者:
*       创建日期:   2024/04/23
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool LkList_TraNode(LkList_t * Head)
{
    //1.先判断链表是否存在
    if(NULL == Head){
        printf("Linklist head is not exist!!!\n");
        return false;
    }
	
	//判断链表是否为空
	if(LkList_IsEmpty(Head)){
		printf("Linklist is empty!!!\n");
		return false;
	}
	
    //备份数据,直接给首结点数据
    LkList_t * Phead = Head->next;
    int i = 1;//输出第几个数据
    //遍历到最后的节点,输出数据
    while(Phead->next){
        printf("[%d]th Node is %d\n",i,Phead->data);
        i++;
        Phead = Phead->next;
    }
    printf("[%d]th Node is %d\n",i,Phead->data);

    return true;
}


修改链表的数据

  • 根据所给对数据,把链表内部的数据修改
/***************************************************
*       函数名称:   LkList_DataRecNode
*       函数功能:   根据数据修改节点
*       函数参数:   
*                   @Head   	:头结点的地址
*					@dest_data	:需要修改的数据
*					@data		:修改的数据
*       返回结果:   true:修改成功;false:修改失败
*       注意事项:   Node
*       函数作者:
*       创建日期:   2024/04/29
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool LkList_DataRecNode(LkList_t * Head,DataType_t dest_data,DataType_t data)
{
	//1.先判断链表是否存在
    if(NULL == Head){
        printf("Linklist head is not exist!!!\n");
        return false;
    }
	
	//判断链表是否为空
	if(LkList_IsEmpty(Head)){
		printf("Linklist is empty!!!\n");
		return false;
	}
	
	//备份头结点对地址,以免丢失链表
	LkList_t *Phead = Head->next;
	
    //寻找到数据节点,并且防止没有这个数据
    while((Phead->data != dest_data) && (Phead->next)){
        Phead = Phead->next;
    }	
	
	//判断数据是否存在
	if((Phead->data != dest_data) && (Phead->next == NULL)){
		printf("dest_data(%d) is not exist!!!\n",dest_data);
        return false;
	}
	
	Phead->data = data;
	
	return true;
}

删除整个链表

/***************************************************
*       函数名称:   LkList_Del
*       函数功能:   删除链表
*       函数参数:   
*                   @Head   :头结点的地址
*       返回结果:   true:删除成功;false:删除失败
*       注意事项:   Node
*       函数作者:
*       创建日期:   2024/04/23
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool LkList_Del(LkList_t * Head)
{
    //1.先判断链表是否存在
    if(NULL == Head){
        printf("Linklist head is not exist!!!\n");
        return false;
    }

    //让Head先向前走,然后后面跟着Head的前驱节点,删除前驱节点
    LkList_t * Head_prev = Head;
    Head = Head->next;
    //遍历到最后的节点,输出数据
    while(Head){
        //Head不为空直接删除直接前驱,
        Head_prev->next = NULL;
        free(Head_prev);

        Head_prev = Head;
        Head = Head->next;
    }
    //Head为空,退出去删除直接前驱和Head本身.
    Head_prev->next = NULL;
    free(Head_prev);
	Head_prev = NULL;
 
    return true;
}

posted @ 2024-05-06 18:59  wuju  阅读(20)  评论(0)    收藏  举报