链表头插法的优化补充、尾插法完结!
头插法的优化补充
这边我们将考虑到可以将动态创建链表,和插入新链表到链表头前方,成为新链表头的方法分开,使其自由度上升,在创建完链表后,还可以添加链表元素到成为新的链表头。
就是说可以单独的调用这个insertHeadBefore这个函数
Tips:
不管尾插法还是头插法都有这段代码,因为如果链表都是空的那肯定要先将new的做头了
尾插法(动态创建)
Tips:p 指针只是一个辅助指针,用于在链表中移动,最终会指向链表的最后一个节点。
还有头插法和尾插法的共同应用
直接上代码
#include <stdio.h>
#include <stdlib.h>
struct Test
{
int data;
struct Test *next;
};
struct Test *insertHeadBefore(struct Test *head,struct Test *new)
{
if(head == NULL){
head = new;
new->next=NULL;
}else{
new->next=head;
head = new;
}
return head;
}
struct Test *insertTailLater(struct Test *head,struct Test *new)
{
struct Test *p;
p = head;
if(p == NULL){ // 链表为空时,直接返回 new 作为新的头节点
head = new;
new->next=NULL;
return head;
}
while(p->next != NULL){
p=p->next;
}
p->next=new;
new->next=NULL;//比如我输入1、2,在2的时候,那么一定要让new->next初始化为NULL不然不能表示链表的状态
//因为你输入new->next=NULL;后链表此时才会变成1->2 表示结尾,也是下一个数字插入的前提
return head;
}
struct Test * createLink1(struct Test *head)
{
struct Test *new;
while(1){
new = (struct Test *)malloc(sizeof(struct Test));
if(new==NULL){
printf("内存分配失败");
return head;
}
printf("请输入data (输入0退出)\n");
scanf("%d",&(new->data));
if(new->data == 0){
printf("quit\n");
free(new);
return head;
}
head = insertHeadBefore(head,new);
}
return head;
}
struct Test * createLink2(struct Test *head)
{
struct Test *new;
while(1){
new = (struct Test *)malloc(sizeof(struct Test));
if(new==NULL){
printf("内存分配失败");
return head;
}
printf("请输入data (输入0退出)\n");
scanf("%d",&(new->data));
if(new->data == 0){
printf("quit\n");
free(new);
return head;
}
head = insertTailLater(head,new);
}
return head;
}
void printfInfo(struct Test *head)
{
struct Test *point = head;
while(point != NULL){
printf("%d ", point->data);
point = point->next;
}
putchar('\n');
}
int main()
{
struct Test *head = NULL;
head = createLink2(head);
printfInfo(head);
struct Test new1 ={1000,NULL};
head = insertHeadBefore(head,&new1);
printfInfo(head);
struct Test new2 ={2000,NULL};
head = insertTailLater(head,&new2);
printfInfo(head);
return 0;
}
认真的问问自己,理解了吗?
这个链表的原理真的要好好理解!!!很重要
Tips:将新节点的 next 指针设置为 NULL 并不仅仅是表示本次插入操作的结束,而是维护链表结构完整性和表示链表结尾的必要操作。下面详细解释这个操作的意义以及与后续输入的关系:
表示链表结束:在单链表结构中,最后一个节点的 next 指针需要设置为 NULL,这是单链表表示结尾的约定。当输入 2 并插入到链表中时,1 节点是原来的最后一个节点,2 是新插入的节点。将 2 节点的 next 指针设置为 NULL,就明确表示 2 是当前链表的最后一个节点,这样在后续遍历链表(例如调用 printfInfo 函数)时,程序可以根据 next 指针是否为 NULL 来判断是否到达链表结尾。
为后续插入做准备:将新节点的 next 指针设置为 NULL 并不意味着链表不再变化。当继续输入 3 时,程序会再次执行 createLink2 函数中的逻辑,为 3 分配新节点,读取输入值 3,然后再次调用 insertTailLater 函数。此时链表状态为 1 -> 2,insertTailLater 函数会遍历链表找到当前的尾节点(即数据为 2 的节点),然后将新节点(数据为 3 的节点)连接到尾节点之后,并将新节点的 next 指针设置为 NULL,链表状态变为 1 -> 2 -> 3。
数据结构的一致性:在链表操作中,保持每个节点的 next 指针正确指向是非常重要的。将最后一个节点的 next 指针设置为 NULL 确保了链表结构的一致性,使得链表的操作(如插入、遍历等)能够正确执行。如果不将新插入的节点的 next 指针设置为 NULL,在后续操作中可能会导致链表遍历错误,因为程序无法正确判断链表的结尾。
综上所述,将新节点的 next 指针设置为 NULL 是维护链表结构完整性和正确处理后续输入的必要步骤,它明确了当前链表的结尾,同时为后续的插入操作提供了正确的链表状态。
单链表插入逻辑里,每次插入一个新节点时,都要把这个新节点视为当前链表的最后一个节点,并且将其 next 指针设为 NULL。下面为你详细解释原因:
单链表结构特点
单链表是一种线性数据结构,由一系列节点构成,每个节点包含数据域和指向下一个节点的指针域。链表的末尾节点没有后续节点,所以其 next 指针要设为 NULL,以此来标志链表的结束。这是单链表的基本规则,保证了链表结构的清晰性和可维护性。