你说C语言链表很难?不是吧!快点进来我告诉你。
前言
很多同学说链表难,总是不懂,看看以下分析就知道了。
预备知识:
1.流程控制
2.数组
3.函数
4.指针
5.字符串
6.结构体
7.Linux简单命令使用
你只有掌握了以上知识点才能更好的掌握C语言链表。以下提供一些我关于指针,字符串,结构体,Linux简单命令使用的知识总结博文链接,这些章节看不懂的同学请点进去。(注意:需要掌握了指针之前的内容才能看懂)
1.指针请点击
2.字符串请点击
3.结构体请点击
4.Linux请点击
1.什么是链表
1.官方定义
C语言链表(C linked list)是一种数据结构,用于在内存中组织和存储数据。它由一系列称为节点(node)的元素组成,每个节点包含数据和一个指向下
一个节点的指针。链表的优势在于可以动态地分配和释放内存空间,并且可
以有效地插入和删除节点。
2.自己理解
1.数组:特点:元素内存地址连续,但对于添加一个元素和删除一个元素不灵活。
2.链表:链表是数据结构——数据存放的思想。特点:链表的每一项都是一个结构体,结构体内可以是指针,指针可以把整个链表串起来。而且链表很灵活。
2.链表的类型
1.单向链表
单向链表(Singly Linked List)中的每个节点只有一个指针,指向下一个节点。最后一个节点的指针指向NULL,表示链表的结束。
2.双向链表
双向链表(Doubly Linked List)中的每个节点有两个指针,一个指向前一个节点,一个指向后一个节点。这样可以实现双向遍历链表。
3.链表的常规操作
1.创建链表:分配内存空间来存储节点,并设置指针的关系。
2.插入节点:在链表的特定位置或开头插入节点,需要调整节点间的指针。
3.删除节点:从链表中删除一个节点,同样需要调整节点间的指针。
4.遍历链表:按顺序访问链表中的每个节点,可以输出节点的数据或进行其他操作。
4.链表和数组区别及实现
1.链表和数组的区别
C语言中,链表(linked list)和数组(array)是两种常见的数据结构,它们有以下几点区别:
1.存储方式:数组是一块连续的内存空间,可以通过索引直接访问任意位置的元素;链表由一系列节点组成,每个节点包含元素和指向下一个节点的指针。
2.动态性:数组的大小在创建时就确定了,并且不能动态地改变大小;链表的大小可以在运行时动态地增加或减少。
3.插入和删除操作:对于数组,插入和删除元素可能需要整体移动后续元素的位置,因为数组中的元素是连续存储的;而链表中插入或删除一个节点只需要修改相邻节点的指针,不需要移动其他节点。
4.内存分配:数组在创建时需要一次性地分配一块连续的内存空间;链表的节点可以分散地存储在不同的内存位置,每个节点可以独立地动态分配。
5.访问效率:数组通过索引可以快速地访问任意位置的元素,时间复杂度为O(1);链表需要遍历链表,时间复杂度为O(n),其中n为链表长度。然而,链表在插入和删除操作上更高效。
2.数组遍历
以下是数组遍历代码
#include <stdio.h>
int main()
{
int i;
int arr[] = {1,2,3};
for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
{
printf("%d ",arr[i]);
}
putchar('\n');
return 0;
}
3.用链表输出1 2 3
1.核心思想:通过在结构体内定义一个结构体指针变量。然后定义三个结构体变量,分别把变量1的指针变量指向变量2,变量2的指针变量指向变量三,实现把数据串起来。形成链表。
2.程序代码
#include <stdio.h>
/*
时间:2023年7月23日20:51:05
程序功能:链表和数组区别及实现
*/
struct Test //定义一个结构体Test
{
int idata; //定义一个整型idata数据
struct Test *next; //定义一个结构体Test指针变量next
};
void introduce()
{
puts("\n\n程序功能:链表和数组区别及实现\n");
puts("struct Test //定义一个结构体Test");
puts("{");
puts(" int idata; //定义一个整型idata数据");
puts(" struct Test *next; //定义一个结构体Test指针变量next");
puts("};\n\n");
puts("struct Test t1 ={1,NULL}; //定义一个结构体变量并为其赋值。");
puts("struct Test t2 ={2,NULL}; //定义一个结构体变量t1,赋值为第一个元素为2,第二个");
puts("struct Test t3 ={3,NULL}; //指针元素指向空。");
puts("t1.next = &t2; //把结构体变量t1中的指针元素next指向第二个结构变量t2");
puts("t2.next = &t3; //把结构体变量t2中的指针元素next指向第三个结构变量t3");
puts("//这样就实现了多个结构体变量串起来。也就形成了链表\n\n");
puts("printf(“%d %d %d杠n”,t1.idata,t1.next->idata,t1.next->next->idata);");
puts("//点号的优先级大于箭号");
puts("");
puts("");
}
int main()
{
int i;
int arr[] = {1,2,3};
introduce();
for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
{
printf("%d ",arr[i]);
}
putchar('\n');
struct Test t1 ={1,NULL}; //定义一个结构体变量并为其赋值。
struct Test t2 ={2,NULL}; //定义一个结构体变量t1,赋值为第一个元素为2,第二个
struct Test t3 ={3,NULL}; //指针元素指向空。
t1.next = &t2; //把结构体变量t1中的指针元素next指向第二个结构变量t2
t2.next = &t3; //把结构体变量t2中的指针元素next指向第三个结构变量t3
//这样就实现了多个结构体变量串起来。也就形成了链表。
printf("以下是用结构体输出数字\n");
printf("%d %d %d\n",t1.idata,t1.next->idata,t1.next->next->idata);//点号的优先级大于箭号
return 0;
}
5.链表静态添加和动态遍历
1.遍历链表函数
void printLlST(struct Test *head) //定义一个遍历链表的函数
{
struct Test *point;
point = head;
while(point != NULL) //判断链表结束标志(NULL)
{
printf("%d ",point->idata);
point = point->next; //移动到下一个元素
}
}
2.核心思想
1.在主函数中多定义一个结构体变量t4并初识化为4,NULL
struct Test t4 = {4,NULL};
2.把原本的结构体变量T3内的指针变量指向T4
t3.next = &t4;
3.最后利用链表遍历函数输出
3.程序代码
#include <stdio.h>
/*
时间: 2023年7月24日17:19:31
程序功能:链表静态添加和动态遍历
*/
struct Test //定义一个结构体Test
{
int idata; //定义一个整型idata数据
struct Test *next; //定义一个结构体Test指针变量next
};
void printLlST(struct Test *head) //定义一个遍历链表的函数
{
struct Test *point;
point = head;
while(point != NULL) //判断链表结束标志(NULL)
{
printf("%d ",point->idata);
point = point->next; //移动到下一个元素
}
}
void introduce()
{
puts("\n\n程序功能:链表静态添加和动态遍历\n");
puts("void printLlST(struct Test *head) //定义一个遍历链表的函数\n");
puts("while(point != NULL) //判断链表结束标志(NULL)\n");
puts("point = point->next; //移动到下一个元素\n");
}
int main()
{
int i;
int arr[] = {1,2,3};
introduce();
for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
{
printf("%d ",arr[i]);
}
putchar('\n');
struct Test t1 = {1,NULL}; //定义一个结构体变量并为其赋值。
struct Test t2 = {2,NULL}; //定义一个结构体变量t1,赋值为第一个元素为2,第二个
struct Test t3 = {3,NULL}; //指针元素指向空。
struct Test t4 = {4,NULL};
t1.next = &t2; //把结构体变量t1中的指针元素next指向第二个结构变量t2
t2.next = &t3; //把结构体变量t2中的指针元素next指向第三个结构变量t3
t3.next = &t4; //这样就实现了多个结构体变量串起来。也就形成了链表。
printf("\n以下是用结构体输出数字\n");
printLlST(&t1);
return 0;
}
4.重点知识研读:point = point->next
请仔细看以下图片内容
6.统计链表节点个数及链表查找
1.输出链表节点个数函数
1.函数代码
int getLinkTotalNodeNum(struct Test *head) //获取链表节点函数
{
int cnt = 0; //定义一个变量cnt用于计数,并初始化为0。
while(head != NULL)
{
cnt++;
head = head->next; //通过指针移动到下一节点
}
return cnt; //返回计数值。
}
2.函数核心思想
函数为整型,形参为结构体指针变量,因此传参为地址。进入函数传参的是t1的地址。判断t1的地址是否为空,不为空cnt自增1为空直接返回 0 。显然第一次不为空,cn自增1,head存放的地址从t1变为t2。这样一直下去,直到head存放的地址为空时,程序退出返回cnt最后的值即节点个数。
2.查找链表节点函数
1.函数代码
int seekLink(struct Test *head,int data) //查找链表节点函数
{
int cnt = 0; //定义一个变量cnt用于判断是否查找到的条件
while(head != NULL)
{
if(head->idata == data)//对比结构体指针变量head所承接的地址中的idata是否等于需要查找的
{
return 1; //是需要查找的返回1
}
head = head->next; //通过指针移动到下一节点
}
return cnt; //不是需要查找的返回 0
}
2.函数核心思想
核心思想函数为整型,形参为结构体指针变量head和一个整型变量data。进入函数第一句为用于返回0好进行判断。进入while循环判断条件为head存放的地址是否为空不为空执行循环体,为空返回零。进入函数head存放的地址为t1的,不为空。进入if判断,如果此时的data的值等于head中的idata的值,则结束函数并返回1,不等于执行下一语句,下一语句为改变head中的地址。一直这样下去,就可以实现查找节点的功能。
3.完整程序代码
#include <stdio.h>
/*
时间: 2023年7月24日20:44:30
程序功能:统计链表节点个数及链表查找
*/
struct Test //定义一个结构体Test
{
int idata; //定义一个整型idata数据
struct Test *next; //定义一个结构体Test指针变量next
};
void printLlST(struct Test *head) //定义一个遍历链表的函数
{
struct Test *point;
point = head;
while(point != NULL) //判断链表结束标志(NULL)
{
printf("%d ",point->idata);
point = point->next; //通过指针移动到下一节点
}
puts("\n");
}
int getLinkTotalNodeNum(struct Test *head) //获取链表节点函数
{
int cnt = 0; //定义一个变量cnt用于计数,并初始化为0。
while(head != NULL)
{
cnt++;
head = head->next; //通过指针移动到下一节点
}
return cnt; //返回计数值。
}
int seekLink(struct Test *head,int data) //查找链表节点函数
{
int cnt = 0; //定义一个变量cnt用于判断是否查找到的条件
while(head != NULL)
{
if(head->idata == data)//对比结构体指针变量head所承接的地址中的idata是否等于需要查找的
{
return 1; //是需要查找的返回1
}
head = head->next; //通过指针移动到下一节点
}
return cnt; //不是需要查找的返回 0
}
void introduce()
{
puts("\n\n程序功能:统计链表节点个数及链表查找\n");
}
int main()
{
int i;
int arr[] = {1,2,3};
int ret; //用于存放返回的节点数
int seekNum; //用于存放需要查找的节点数
int seekLinkResult; //用于存放查找出的节点的结果
introduce();
for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
{
printf("%d ",arr[i]);
}
putchar('\n');
struct Test t1 = {1,NULL}; //定义一个结构体变量并为其赋值。
struct Test t2 = {2,NULL}; //定义一个结构体变量t1,赋值为第一个元素为2,第二个
struct Test t3 = {3,NULL}; //指针元素指向空。
struct Test t4 = {4,NULL};
t1.next = &t2; //把结构体变量t1中的指针元素next指向第二个结构变量t2
t2.next = &t3; //把结构体变量t2中的指针元素next指向第三个结构变量t3
t3.next = &t4; //这样就实现了多个结构体变量串起来。也就形成了链表。
printf("\n以下是用结构体输出数字\n");
printLlST(&t1);
ret = getLinkTotalNodeNum(&t1);
printf("链表的节点个数为 total num = %d\n",ret);
puts("请输入你要查找的节点");
scanf("%d",&seekNum);
seekLinkResult = seekLink(&t1,seekNum);
if(seekLinkResult == 1)
{
printf("在链表中存在你查找的节点 %d\n",seekNum);
}
else
{
printf("在链表中不存在你查找的链表节点 %d\n",seekNum);
}
return 0;
}
7.链表从指定节点后方插入新节点
1.查找并插入节点函数
1.函数代码
void sNodeInsNewN(struct Test *head,int data,struct Test *new)//查找并插入节点函数
{
struct Test *p =head;
while(p != NULL)
{
if(p->idata == data)
{
new->next = p->next;
p->next = new;
}
p = p->next;
}
}
2.函数核心思想1
函数类型为空,形参分别为结构体指针变量head,整型变量data,结构体指针变量new进入函数,首先定义一个结构体指针变量p用于承接head的地址,head中的地址为t1的地址,判断p的地址相当于判断t1的地址是否为空。不为空,进入if语句。判断p中的idata是否等于data,如果data的值等于1,则成立。因为t1中的data的值为1。进入if语句执行体内,执行插入节点功能,先把p中的next赋给new中的next。然后把new的地址赋给p中的next。实现插入节点。如果idata != data,则不会执行插入节点操作。最后执行通过指针实现移动节点。
3.函数核心思想2:研读new->next = p->next; p->next = new;
请仔细看以下图片内容
2.完整程序代码
#include <stdio.h>
/*
时间: 2023年7月24日23:45:33
程序功能:链表从指定节点后方插入新节点
*/
struct Test
{
int idata;
struct Test *next;
};
void printList(struct Test *head) //输出链表函数
{
struct Test *p = head;
while(p != NULL)
{
printf("%d ",p->idata);
p = p->next;
}
putchar('\n');
}
void sNodeInsNewN(struct Test *head,int data,struct Test *new)//查找并插入节点函数
{
struct Test *p =head;
while(p != NULL)
{
if(p->idata == data)
{
new->next = p->next;
p->next = new;
}
p = p->next;
}
}
int main()
{
int seekNum;
char yesOrNoC;
struct Test t1 = {1,NULL};
struct Test t2 = {2,NULL};
struct Test t3 = {3,NULL};
struct Test t4 = {4,NULL};
struct Test t5 = {5,NULL};
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
puts("\n程序功能:链表从指定节点后方插入新节点\n");
do
{
puts("\n请输入你要在哪个节点后插入\n");
scanf("%d",&seekNum);
struct Test new;
puts("\n请输入你要插入的数据\n");
scanf("%d",&new.idata);
new.next = NULL;
puts("\n初始链表输出结果如下:\n");
printList(&t1);
puts("\n插入新节点后链表为\n");
if(seekNum>=1 && seekNum<=5)
{
sNodeInsNewN(&t1,seekNum,&new);
printList(&t1);
//重新初识化链表,不然循环到后面会出问题,链表断开。
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
t5.next = NULL;
}
else
{
puts("插入节点失败,因为指定位置超出1~5");
}
puts("\n是否继续插入新节点 y/n \n");
getchar();
scanf("%c",&yesOrNoC);
}while(yesOrNoC=='y' || yesOrNoC=='Y');
puts("程序结束!!!");
return 0;
}
8.链表从指定节点前方插入新节点
1.查找并插入节点函数
1.函数代码
struct Test* sNodeInsNewN(struct Test *head,int data,struct Test *new)
{
struct Test *p = head;
if(p->idata == data)
{
new->next = head;
puts("插入节点成功\n");
return new;
}
while(p->next != NULL)
{
if(p->next->idata == data)
{
new->next = p->next;
p->next = new;
puts("插入节点成功\n");
return head;
}
p = p->next;
}
puts("插入节点失败!因为指定位置超出范围,原样输出。\n");
return head;
}
2.函数核心思想
请仔细看以下图片内容
2.完整程序代码
#include <stdio.h>
/*
时间: 2023年7月26日01:07:03
程序功能:链表从指定节点前方插入新节点
*/
struct Test
{
int idata;
struct Test *next;
};
void printList(struct Test *head)
{
struct Test *p = head;
while(p != NULL)
{
printf("%d ",p->idata);
p = p->next;
}
puts("\n");
}
struct Test* sNodeInsNewN(struct Test *head,int data,struct Test *new)
{
struct Test *p = head;
if(p->idata == data)
{
new->next = head;
puts("插入节点成功\n");
return new;
}
while(p->next != NULL)
{
if(p->next->idata == data)
{
new->next = p->next;
p->next = new;
puts("插入节点成功\n");
return head;
}
p = p->next;
}
puts("插入节点失败!因为指定位置超出范围,原样输出。\n");
return head;
}
int main()
{
int seekNum;
char yesOrNoC;
struct Test t1 = {1,NULL};
struct Test t2 = {2,NULL};
struct Test t3 = {3,NULL};
struct Test t4 = {4,NULL};
struct Test t5 = {5,NULL};
struct Test new;
struct Test *head;
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
head = &t1;
puts("\n程序功能:链表从指定节点前方插入新节点\n");
puts("\n初始化链表输出如下。\n");
printList(&t1);
do
{
puts("\n请输入你需要插入的节点位置\n");
scanf("%d",&seekNum);
puts("\n请输入你要插入的数据\n");
scanf("%d",&new.idata);
putchar('\n');
new.next = NULL;
head = sNodeInsNewN(&t1,seekNum,&new);
printList(head);
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
head = &t1;
puts("你是否继续插入节点?y/n\n");
getchar();
scanf("%c",&yesOrNoC);
}while(yesOrNoC=='y' || yesOrNoC=='Y');
puts("\n程序结束!!!");
return 0;
}
9.链表删除指定节点
1.查找并删除节点函数
1.函数代码
struct Test *deleteNode(struct Test *head,int data)
{
struct Test *p = head;
if(p->idata == data) //注意逻辑等于 ==
{
puts("\n删除节点成功输出\n");
head = head->next;
return head;
}
while(p->next != NULL)
{
if(p->next->idata == data)
{
p->next = p->next->next;
puts("\n删除节点成功输出\n");
return head;
}
p = p->next;
}
puts("删除节点失败,输入节点超出范围!原样输出\n");
return head;
}
2.函数核心思想
请仔细看以下图片内容
2.完整程序代码
#include <stdio.h>
/*
时间: 2023年7月26日22:51:27
程序功能:链表删除指点节点
*/
struct Test
{
int idata;
struct Test *next;
};
void printList(struct Test *head)
{
struct Test *p = head;
while(p != NULL)
{
printf("%d ",p->idata);
p = p->next;
}
puts("\n");
}
struct Test *deleteNode(struct Test *head,int data)
{
struct Test *p = head;
if(p->idata == data) //注意逻辑等于 ==
{
puts("\n删除节点成功输出\n");
head = head->next;
return head;
}
while(p->next != NULL)
{
if(p->next->idata == data)
{
p->next = p->next->next;
puts("\n删除节点成功输出\n");
return head;
}
p = p->next;
}
puts("删除节点失败,输入节点超出范围!原样输出\n");
return head;
}
int main()
{
int seekNum;
char yesOrNoC;
struct Test t1 = {1,NULL};
struct Test t2 = {2,NULL};
struct Test t3 = {3,NULL};
struct Test t4 = {4,NULL};
struct Test t5 = {5,NULL};
struct Test *head;
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
head = &t1;
puts("\n程序功能:链表删除指点节点\n");
puts("\n初始化链表输出\n");
printList(&t1);
do
{
puts("\n请输入你要删除的节点数\n");
scanf("%d",&seekNum);
head = deleteNode(head,seekNum);
printList(head);
//重置链表
t1.next = &t2;
t2.next = &t3;
t3.next = &t4;
t4.next = &t5;
head = &t1;
puts("是否继续删除链表节点?y/n\n");
getchar();
scanf("%c",&yesOrNoC);
}while(yesOrNoC=='y' || yesOrNoC=='Y');
puts("\n程序结束!!!\n");
return 0;
}
10.链表动态创建之头插法
1.动态创建链表头插法函数
1.函数代码
struct Test *InsertFormHead(struct Test *head) //动态创建链表头插法函数
{
struct Test *new;
while(1)
{
new = (struct Test *)malloc(sizeof(struct Test));
puts("\n请输入你要插入的节点数据\n");
scanf("%d",&(new->idata));
new->next = NULL;
if(new->idata == 0)
{
puts("\n你输入的数据为0,不符合!程序退出。\n");
return head;
}
if(head == NULL)
{
head = new;
}
else
{
new->next = head;
head = new;
}
}
}
2.函数核心思想
请仔细看以下图片内容
2.整个程序代码
#include <stdio.h>
#include <stdlib.h>
/*
时间: 2023年7月28日01:04:56
程序功能:链表动态创建之头插法(基础版)
*/
struct Test
{
int idata;
struct Test *next;
};
void printList(struct Test *head)
{
struct Test *p = head;
while(p != NULL)
{
printf("%d ",p->idata);
p = p->next;
}
puts("\n");
}
struct Test *InsertFormHead(struct Test *head) //动态创建链表头插法函数
{
struct Test *new;
while(1)
{
new = (struct Test *)malloc(sizeof(struct Test));
puts("\n请输入你要插入的节点数据\n");
scanf("%d",&(new->idata));
new->next = NULL; //不为new中的结构体指针变量next赋空,会出现输出时死循环,
if(new->idata == 0) //因为没有赋值时next为野指针。历循地址时会出错。
{
puts("\n你输入的数据为0,不符合!程序退出。\n");
return head;
}
if(head == NULL)
{
head = new;
}
else
{
new->next = head;
head = new;
}
}
}
struct Test *freeList(struct Test *head)//释放动态链表内存函数
{
struct Test *p = head;
while(p != NULL)
{
p = p->next; //先让p历循到下一节点
free(head); //再把链表头内存释放掉
head = p; //最后把下一节p点赋给head
//依次循环下去即可把动态创建的链表内存空间释放。
}
return head;
}
int main()
{
struct Test * head = NULL;
char yesOrNoC;
puts("\n程序功能:链表动态创建之头插法(基础版)\n");
do
{
head = InsertFormHead(head);
printList(head);
head = freeList(head);
puts("你是否继续动态创建链表?y/n\n");
getchar();
scanf("%c",&yesOrNoC);
}while(yesOrNoC=='y' || yesOrNoC=='Y');
puts("\n程序退出!!!");
return 0;
}
3.整个程序代码改进版——改进就只是把头插法和动态创建链表分别封装成一个函数
#include <stdio.h>
#include <stdlib.h>
/*
时间: 2023年7月28日01:04:56
程序功能:链表动态创建之头插法(优化版)
*/
struct Test
{
int idata;
struct Test *next;
};
void printList(struct Test *head)
{
struct Test *p = head;
while(p != NULL)
{
printf("%d ",p->idata);
p = p->next;
}
puts("\n");
}
struct Test *InsertFormHead(struct Test *head,struct Test *new)
{
if(head == NULL)
{
head = new;
}
else
{
new->next = head;
head = new;
}
return head;
}
struct Test *createList(struct Test *head)
{
struct Test *new;
while(1)
{
new = (struct Test *)malloc(sizeof(struct Test));
puts("\n请输入你要插入的节点数据\n");
scanf("%d",&(new->idata));
new->next = NULL;
if(new->idata == 0)
{
puts("\n你输入的数据为0,不符合!程序退出。\n");
free(new);
return head;
}
head = InsertFormHead(head,new);
}
}
struct Test *freeList(struct Test *head)//释放动态链表内存函数
{
struct Test *p = head;
while(p != NULL)
{
p = p->next; //先让p历循到下一节点
free(head); //再把链表头内存释放掉
head = p; //最后把下一节p点赋给head
//依次循环下去即可把动态创建的链表内存空间释放。
}
return head;
}
int main()
{
struct Test * head = NULL;
char yesOrNoC;
puts("\n程序功能:链表动态创建之头插法(基础版)\n");
do
{
head = createList(head);
printList(head);
head = freeList(head);
puts("你是否继续动态创建链表?y/n\n");
getchar();
scanf("%c",&yesOrNoC);
}while(yesOrNoC=='y' || yesOrNoC=='Y');
puts("\n程序退出!!!");
return 0;
}
11.链表动态创建之尾插法
1.动态创建链表尾插法函数
1.函数代码
struct Test *InsertFormTail(struct Test *head,struct Test *new) //动态创建链表尾插法函数
{
struct Test *p = head;
if(p == NULL)
{
head = new;
return head;
}
while(p->next != NULL)
{
p = p->next;
}
p->next = new;
return head;
}
2.函数核心思想
请仔细看以下图片内容
2.释放动态创建链表的函数
1.函数代码
struct Test *freeList(struct Test *head)
{
struct Test *tmp = head;
while(tmp != NULL)
{
tmp = tmp->next;
free(head);
head = tmp;
}
return head;
}
2.函数核心思想
请仔细看以下图片内容
3.完整程序代码
#include <stdio.h>
#include <stdlib.h>
/*
时间: 2023年7月29日00:51:12
程序功能:链表动态创建之尾插法
*/
struct Test
{
int idata;
struct Test *next;
};
void *printList(struct Test *head)//输出链表函数。
{
struct Test *p = head;
while(p != NULL)
{
printf("%d ",p->idata);
p = p->next;
}
puts("\n");
}
struct Test *InsertFormTail(struct Test *head,struct Test *new)
{ //动态创建链表尾插法函数
struct Test *p = head;
if(p == NULL)
{
head = new;
return head;
}
while(p->next != NULL)
{
p = p->next;
}
p->next = new;
return head;
}
struct Test *createList(struct Test *head)//动态创建链表函数
{
struct Test *new;
while(1)
{
new = (struct Test *)malloc(sizeof(struct Test));
puts("\n请输入你要插入的节点数据\n");
scanf("%d",&(new->idata));
new->next = NULL;
if(new->idata == 0)
{
puts("\n输入的节点数据为零,不符合,输入结束!\n");
free(new);
return head;
}
head = InsertFormTail(head,new);
}
}
struct Test *freeList(struct Test *head)//释放动态创建链表内存函数。
{
struct Test *tmp = head;
while(tmp != NULL)
{
tmp = tmp->next;
free(head);
head = tmp;
}
return head;
}
int main()
{
struct Test *head = NULL;
char yesOrNoC;
puts("\n程序功能:链表动态创建之尾插法\n");
do
{
head = createList(head);
printList(head);
head = freeList(head);
puts("你是否继续用尾插法创建动态链表?y/n\n");
getchar();
scanf("%c",&yesOrNoC);
}while(yesOrNoC=='y' || yesOrNoC=='Y');
puts("\n程序结束!!!");
return 0;
}
结束语
您能在百忙之中抽出时间看到这里,我很感谢,也很高兴。链表的难点在于你对链表之前的知识是否掌握足够扎实,链表是一种数据存放的思想,所以只要你之前的知识掌握好,链表还是能够独立完成的。