欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > 《数据结构:C语言实现单链表》

《数据结构:C语言实现单链表》

2025/3/19 6:27:31 来源:https://blog.csdn.net/2401_83305953/article/details/140389954  浏览:    关键词:《数据结构:C语言实现单链表》

文章目录

    • 一、单链表
        • 1、概念与结构
        • 2、结点
        • 3、链表的性质
    • 二、实现单链表
        • 1、创建单链表的结构体
        • 2、头部数据插入
        • 3、尾插数据
        • 4、头删和尾删数据
        • 5、查找数据
        • 6、在任意位置之前增加数据
        • 7、删除结点
        • 8、删除结点之后的结点
        • 9、在结点之后插入数据
        • 10、销毁链表
    • 三、代码
        • SListNode.h
        • SListNode.c

一、单链表

1、概念与结构

概念:链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

2、结点

单链表与顺序表不同的是,链表的每个空间是独立申请的,称为一个结点。

  • 结点的组成主要由两个部分:当前结点要保存数据和下一个结点的地址(指针变量)。

所以在动态申请空间时使用malloc函数开辟空间就可以了。

3、链表的性质
  • 1、链式机构在逻辑上是连续的,在物理结构上不⼀定连续
  • 2、结点⼀般是从堆上申请的
  • 3、从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续

假设当前保存的结点为整形的结构体代码:

struct SListNode
{
int data; //结点数据
struct SListNode* next; //指针变量⽤保存下⼀个结点的地址
};

当我们想要保存⼀个整型数据时,实际是向操作系统申请了⼀块内存,这个内存不仅要保存整型数据,也需要保存下⼀个结点的地址(当下⼀个结点为空时保存的地址为空)。
当我们想要从第⼀个结点⾛到最后⼀个结点时,只需要在当前结点拿上下⼀个结点的地址就可以了。

二、实现单链表

1、创建单链表的结构体

创建一个名为SListNode.h的头文件
向SListNode.h输入如下代码:

在这里插入图片描述

用typedef 给要存储的数据重命名,也给单链表结构体重命名一个简单的名字SLTNode

2、头部数据插入

创建一个test.c文件用来测试程序
创建一个SListNode.c文件完成函数的定义
把函数声明放置在SListNode.h的头文件中
在test.c文件中进行主函数调用test1()函数进行测试,在test1()中创建一个单链表结构体变量,前提包含了#include"SListNode.h",完成创建。

test.c:
在这里插入图片描述

传址调用,通过地址可以完成形参改变实参

SListNode.h:
在这里插入图片描述

传参是一级指针的地址用二级指针接收

SListNode.c:
在这里插入图片描述

先断言,保存数据申请空间,在创建一个开辟空间的函数,在开辟空间把要保存的数据传过去保存,空间不连续用malloc开辟

再完成一个打印数据的函数
不是通用的,现在打印的是整形数据

在这里插入图片描述
在这里插入图片描述

测试成功

3、尾插数据

在这里插入图片描述

要考虑两种情况,在一个数据都没有时第一个节点就是首尾结点。
在有数据的情况下,要找到最后一个结点,最后一个结点存放的指针指向的地址为NULL,把这个节点的指针指向为新结点。

4、头删和尾删数据

头删:
在这里插入图片描述
尾删:
在这里插入图片描述

5、查找数据

在这里插入图片描述
使用方法:
在这里插入图片描述

查找功能可以返回动态内存的空间,方便我们去在任意位置之前增删,结合使用。

6、在任意位置之前增加数据

test测试:
在这里插入图片描述

在数据为5的结点前面插入新结点,要传三个值,第一个是首结点,第二个要在哪个结点之前插入结点,第三个插入的数据值。

代码实现:
在这里插入图片描述

思路在开辟新结点,需要用首结点找到插入结点之前的结点,让之前结点指向新结点,新结点指向被插入的结点。
特殊情况在被插入数据结点是首结点时,前面没有结点,直接调用头插。

7、删除结点

同样是用查询找到被删数据的结点在进行调用函数删除。

在这里插入图片描述

8、删除结点之后的结点

在这里插入图片描述

9、在结点之后插入数据

在这里插入图片描述

10、销毁链表

在这里插入图片描述

三、代码

SListNode.h
#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int SLTDATETYPE;typedef struct SListNode
{SLTDATETYPE date;//结点数据struct SListNode* next;//指针保存下一个结点的地址
}SLTNode;//单链表头部插入数据
void SLTPushFornt(SLTNode** pps, SLTDATETYPE x);//打印数据
void SLTPrint(SLTNode* ps);//单链表尾部插入数据
void SLTPushBack(SLTNode** pps, SLTDATETYPE x);//单链表头部删除数据
void SLTPopFornt(SLTNode** pps);//单链表尾部删除数据
void SLTPopBack(SLTNode** pps);//查找数据返回数组的空间
SLTNode* SLTFind(SLTNode* ps, SLTDATETYPE x);//在任意位置之前插入数据
void SLTInsert(SLTNode** pps,SLTNode* pos, SLTDATETYPE x);//在结点之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDATETYPE x);//删除结点
void SLTErase(SLTNode** pps, SLTNode* pos);//删除结点之后的结点
void SLTEraseAfter(SLTNode* pos);//销毁链表
void SLTDestroy(SLTNode** pps);
SListNode.c
#include"SListNode.h"//申请结点空间
SLTNode* SLTBuyNode(SLTDATETYPE x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){//申请失败perror("malloc full");exit(1);}newnode->date = x;newnode->next = NULL;return newnode;
}//单链表头部插入数据
void SLTPushFornt(SLTNode** pps, SLTDATETYPE x)
{assert(pps != NULL);//先开辟空间SLTNode* newnode = SLTBuyNode(x);newnode->next = *pps;*pps = newnode;
}//打印数据
void SLTPrint(SLTNode* ps)
{while (ps != NULL){printf("%d->", ps->date);ps = ps->next;}printf("NULL\n");
}//单链表尾部插入数据
void SLTPushBack(SLTNode** pps, SLTDATETYPE x)
{assert(pps != NULL);SLTNode* newnode = SLTBuyNode(x);if (*pps == NULL){*pps = newnode;}else{SLTNode* pcur = *pps;while (pcur->next){pcur = pcur->next;}pcur->next = newnode;}
}//单链表头部删除数据
void SLTPopFornt(SLTNode** pps)
{assert(pps != NULL);//如果首节点为空没有数据可删了assert(*pps != NULL);//保存下一个结点的地址//删除首结点后下一个结点成为首结点SLTNode* pcur = (*pps)->next;free(*pps);*pps = pcur;
}//单链表尾部删除数据
void SLTPopBack(SLTNode** pps)
{assert(pps != NULL);assert(*pps != NULL);//如果只有一个数据就直接删除//找尾节点SLTNode* pcur = *pps;if (pcur->next == NULL){free(*pps);*pps = NULL;}else{//保存尾结点的上一结点//因为尾结点被删,它成为尾结点,结点指针指向NULLSLTNode* prev = *pps;while (pcur->next){prev = pcur;pcur = pcur->next;}prev->next = NULL;}
}//查找数据返回数组的空间
SLTNode* SLTFind(SLTNode* ps, SLTDATETYPE x)
{while (ps){if (ps->date == x)return ps;ps = ps->next;}return NULL;
}//在任意位置之前插入数据
void SLTInsert(SLTNode** pps, SLTNode* pos, SLTDATETYPE x)
{assert(pps != NULL);assert(pos != NULL);if (*pps == pos){//头结点头插SLTPushFornt(pps, x);}else{SLTNode* newnode = SLTBuyNode(x);SLTNode* pcur = *pps;while (pcur->next != pos){pcur = pcur->next;}pcur->next = newnode;newnode->next = pos;}
}//在结点之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDATETYPE x)
{assert(pos != NULL);SLTNode* pcur = pos->next;SLTNode* newnode = SLTBuyNode(x);pos->next = newnode;newnode->next = pcur;}//删除结点
void SLTErase(SLTNode** pps, SLTNode* pos)
{assert(pps != NULL);assert(pos != NULL);if (*pps == pos){SLTPopFornt(pps);}else{SLTNode* pcur = *pps;while (pcur->next != pos){pcur = pcur->next;}pcur->next = pos->next;free(pos);pos = NULL;}
}//删除结点之后的结点
void SLTEraseAfter(SLTNode* pos)
{assert(pos != NULL && pos->next != NULL);SLTNode* pcur = pos->next->next;free(pos->next);pos->next = pcur;
}//销毁链表
void SLTDestroy(SLTNode** pps)
{assert(pps != NULL);SLTNode* pcru = *pps;SLTNode* next = *pps;while (pcru){next = pcru->next;free(pcru);pcru = next;}*pps = NULL;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词