在学习之前,可以温故一下结构体的知识,明白结构体变量和结构体指针,可以看我的一篇博客:https://blog.youkuaiyun.com/a1130683021/article/details/134595804?spm=1001.2014.3001.5501
链表的概念
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
剖析概念,我们得到几个关键词:非连续、非顺序、指针链接次序。通过了解链表的结构,我们很快就能明白这些关键词的含义
链表的结构
链表由一个又一个节点,通过指针进行连接。每个节点中会存在两个域,一个是数据域,另一个是指针域。数据域用来存储数据,指针域用来链接节点。思考什么数据结构可以去胜任节点呢?当然是结构体。因此,结构体就是充当节点,每一个结构体都包括存储数据的变量,以及结构体指针——用于指向结构体变量。


从图中我们不难发现,节点与节点之间是通过结构体指针进行链接的,而节点之间是离散的,在内存里是这里一个那里一个,并不像数组空间一样连续。
单向链表的实现
一.节点的创建
1. 声明结构体类型
struct Node {
//数据域,存储数据
int data;
char name[10];
//指针域,用于指向结构体变量(节点)
struct Node* next;
};
由于节点是结构体,并且是Node类型的结构体,因此我们需要定义Node类型的结构体指针。
2.节点的创建
于是,我们可以通过Node结构体类型进行节点的创建。
struct Node node1,node2;
二.链表逻辑以及代码
重要引入
头指针指向链表的头节点,一个链表需要头指针,为什么?因为我们需要用链表。类比数组的使用,我们需要知道数组的首地址,通过指针移动的方式进行访问。链表同理,我们需要知道链表的头指针,通过头指针去进行指针的移动,对链表进行操作。一般,头节点的数据域不放数据。
我们都知道将思路转化为编程语言是一大难点,该如何去安排语句呢?思路上,我们是需要创建多个节点的,但是,假如我需要10000个节点,我总不能死板的一口气创建10000个节点吧?所以我们需要使用到循环,将创建节点的语句放入循环中。但是这样就有一个问题:当我们下一次循环再次创建节点的时候,我便失去了上一次循环创建的节点的地址(类比于循环中放入定义变量的语句,每一次循环都是重新定义变量,这会导致上一次变量数据的丢失)。因此我们需要通过一个结构体指针来存储上一个节点的地址。为了方便操作,我们也可以定义一个结构体指针来指向新的节点。
代码以及图解
/*
pnew 新的节点
pend 上一个节点
head 头指针
*/
int count = 0;//表示是当前第几个节点,从0开始
struct Node* create()
{
int cnt;//链表的长度
printf("请输入链表长度:\n");
scanf("%d", &cnt);
struct Node* pnew, * pend;//定义结构体指针
struct Node* head = NULL;//定义头指针并置于NULL
/*
malloc用于在堆中开辟空间,如下文代码中,开辟了Node大小的内存空间
并且返回了一个Node类型的结构体指针
malloc返回一个Node类型的指针给pnew,pnew指向一个节点的地址
*/
pnew = (struct Node*)malloc(sizeof(struct Node));
while (count <= cnt)
{
if (count == 0)
{
//见图1
pnew->next = NULL;//将next指针置空,告诉编译器这里是当前链表终点
//以下两步将pnew以及pend都置于头节点
head = pnew;
pend = pnew;
}
else {
//见图2
pnew = (struct Node*)malloc(sizeof(struct Node));//申请一个新的节点
scanf("%s", &pnew->name);//输入数据
scanf("%d", &pnew->data);
pnew->next = NULL;//指针置空
pend->next = pnew;//节点的链接
pend = pnew;//新的节点变成了旧的节点
}
count++;
}
return head;//返回头指针
}
附图1:

附图2

创建结束后的链表
由附图二我们可以看出,pend移动之后,上一个节点的地址将会丢失,当前节点变成旧节点,以便为了继续连接新的节点。因此在链表被完全创建完之后,pnew以及pend会指向最后一个节点,head依旧指向头节点,没有变过。

三.遍历链表
void Input(struct Node* head)
{
//我们要判断是否存在下一个节点,如果不存在,head->next即为NULL
//见图三
head = head->next;
while (head != NULL)
{
printf("%d\t%s\n", head->data, head->name);
head = head->next;
}
}

通过头指针,我们可以移动指针来遍历链表。首先,我们将head指针移动到它的next位置,也就是head = head->next。如果head为NULL,则代表链表到了终点,跳出循环。
待更





