链表的尾插法(郝斌老师数据结构链表代码分析)

前言

今天学习到数据结构里的尾插法(郝斌老师的数据结构),发现很多初学者对于视频所讲的尾插法的代码有些疑惑(尽管我也是个小白),下面我们来对其分析一下 下附代码

二、代码示例

这里我把老师在课堂上讲的代码搬过来
没看过视频的可以先看这个较为完整的代码
看过视频的同学可以直接跳过看下一个代码:

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
 
typedef struct Node	
{
	int data;	//数据域
	struct Node *next;	//指针域 
} NODE,*PNODE;
 
PNODE create_list(void);
void traverse_list(PNODE pHead);
 
 
int main(void)
{
	PNODE pHead=NULL;	//
	pHead=create_list();		//创建一个非循环单链表,并将改链表的头结点的地址赋值给pHead 
	traverse_list(pHead);
	
	return 0; 
 }
 
PNODE create_list(void)
{
	int len;	//用来存放有效结点的个数 
	int i;
	int val;	//用来临时存放用户输入的结点的值 
	
	PNODE pHead=(PNODE)malloc(sizeof(NODE));	//此处地方的PHead与下面的PHead无关系,这里的是一个局部变量 
	if(pHead==NULL)
	{
		printf("分配失败,程序终止!\n");
		exit(-1);
	 } 
 
	PNODE pTail=pHead;
	 pTail->next=NULL;	
 
	printf("请输入你需要生成链表结点的个数:len=");
	scanf("%d",&len);
	for(i=0;i<len;i++)
	{
		printf("请输入%d个结点的值:",i+1);
		scanf("%d",&val);
		
		//需要一个接受专门接受数据的新节点
		PNODE pNew=(PNODE)malloc(sizeof(NODE));	
		if(NULL==pNew)
		{
			printf("分配失败,程序终止!\n");
			exit(-1);
	 	} 
		pNew->data =val;  //这里如何理解?
		pTail->next=pNew; //这里如何理解?
		pNew->next=NULL;  //这里如何理解?
		pTail=pNew;		  //这里如何理解? 
		
	} 
	
	
	return pHead;
}
void traverse_list(PNODE pHead)
{
	.....
}

上面的代码有些多
所以我们将最核心的代码单独拿出来
我们可以仅看下面的代码:

首先我们来对n,m两行(暂且就这么叫)以及最下面的四行代码进行分析

	PNODE pTail=pHead;  //n行
	pTail->next=NULL;	//m行

n行
这里定义了一个PNODE(struct Node *)类型指针,变量名为pTail,并且将pHead中保存的地址赋给pTail
m行
将pTail所指向的结构体中的指针域清空

然后我们来分析最后的四行代码

	pNew->data =val;  
	pTail->next=pNew; //关键操作
	pNew->next=NULL; 
	pTail=pNew;		  //这里如何理解? 

我们来逐行分析
第一行 :pNew->data =val;
将val 赋给 pNew所指向的结构体中的数据域,这个pNew是什么呢?
没错,它也是个指针,需要注意的是我们在这里说的指针内存的关系
第二行:pTail->next=pNew;
将pNew的地址赋给pTail所指向的结构体中的指针域
第三行:pNew->next=NULL;
将pNew所指向的所指向的结构体中的指针域清空
第四行:pTail=pNew;
将pNew的地址赋给pTail

到了这里,相信大家有一些朦胧感觉了
不要着急,我们继续深入一下
需要注意的是,我们在这个过程中从未直接操作内存,我们一直是通过指针来操作的,
我们知道,如果链表只有一个元素时头结点尾节点是相同的,
在n行代码哪里我们已经知道头结点,并且将头结点的地址发送给了pTail,这就使pTail也指向了头结点,但是此时的链表里是没有元素的,所以pTail也指向了尾节点,而m行将头结点的指针域清空也就使它变成了一个尾节点,我们的目的也就是将它变成一个尾节点
如果你理解了上面几句的含义,那么最后的四行代码就没有什么难度了,
创建一个新的动态内存,并把内存的地址传给pNew,然后将val 赋给 pNew所指向的结构体中的数据域,
然后将pNew的地址赋给pTail所指向的结构体中的指针域,这里就是灵魂操作了哦,这一句代码就将pNew所指向的内存挂到了pHead所指向的内存(也就是头结点)的后面,
所以。。。。为什么?
我们不要忘了,此时的pTail里保存的东西是什么,就是头结点的地址啊,但是pTail是指向尾节点的啊
所以我们要把pNew所指向的指针域清空,让它变成一个尾节点,
然后,我们要做的仅仅是更新pTail中保存的地址就可以了

尾插法创建单链表


总结

我觉得这个代码让我印象最深的地方是在哪里呢,是在pTail->next=pNew;这一行,当时我一直想不明白pTail->next接收pNew的地址有什么用,我在看视频时的弹幕上也没有找到我想要的答案,有的在说画个图就理解了,但是我画了半天也没画明白,后来我就没去管它,去吃饭了,吃饭的时候我就觉得我可能想偏了,我把内存和指针给搞混了(因为弹幕上有人在刷pTail是个替身什么的,我就把它给想成是内存了),我觉得替身这个词不好,应该换一个,

烤肠比较好,pTail就相当于在原来pHead这根签子已经插到烤肠(内存)里的基础上又扎了根签儿。。。

就到这里吧,如果这篇文章对你有帮助当然是最好的了,大家一起努力,能看到我这个文的估计和我水平相差无几,我也只是一个普通的大学生而已,一起努力呗(这其实是我的第一个案例分析,上面有什么不对的地方希望各位大神能指点我一下)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值