接上篇:https://blog.csdn.net/m0_37957160/article/details/108685364
例子:写一函数以删除动态链表中指定的结点。
解题思路:
1、从p指向的第一个结点开始,检查该结点中的num值是否等于输入的要求删除的那个学号。
2、如果相等就将该结点删除,如不相等,就将p后移一个结点(继续寻找 ),再如此下去,直到遇到表尾为止。
3、可以设两个指针变量p1和p2,先使p1指向第一个结点。
4、如果要删除的不是第一个结点,则使p1后移指向下一个结点(将p1->next赋给p1),在此之前将p1的值赋给p2,使p2指向刚才检查过的那个结点(为什么要这样呢?因为刚才的那个图我们知道我们要实现删除操作C,必须这个结点B的next指向后一个结点D的地址,所以这个p2还是必须要先指向B保留一下,之后p2的next才能指向p1)。
算法流程图:
代码如下:(先创建链表在删除结点)
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define LEM sizeof(struct student)//student结构大小
struct student *create();//创建链表
struct student *del(struct student *head,int num);//del函数用于删除结点,*head即链表的头指针,num是要删除的结点num
void print(struct student *head);//打印链表
struct student
{
int num;
float score;
struct student *next
};
int n;//全局变量,用来记录存放了多少数据
void main()
{
struct student *stu,*p;
int n;
stu=creat();
p=stu;
print(p);
printf("Please enter the num to delete:");
scanf("%d",&n);
print(del(p,n));
printf("\n\n");
system("pause");
}
struct student *creat()
{
struct student *head;
struct student *p1, *p2;
p1 = p2 = (struct student *)malloc(LEN); // LEN是student结构的大小
printf("Please enter the num :");
scanf("%d", &p1->num);
printf("Please enter the score :");
scanf("%f", &p1->score);
head = NULL;
n = 0;
while( p1->num )
{
n++;
if( 1 == n )
{
head = p1;
}
else
{
p2->next = p1;
}
p2 = p1;
p1 = (struct student *)malloc(LEN);
printf("\nPlease enter the num :");
scanf("%d", &p1->num);
printf("Please enter the score :");
scanf("%f", &p1->score);
}
p2->next = NULL;
return head;
}
void print(struct student *head)
{
struct student *p;
printf("\nThere are %d records!\n\n", n);
p = head;
if( head )
{
do
{
printf("学号为 %d 的成绩是: %f\n", p->num, p->score);
p = p->next;
}while( p );
}
}
struct student *del(struct student *head,int num)//1指向struct student结构的指针
{
struct student *p1,*p2;//2指向结构的指针
if(NULL==head)//3我们要判断上边函数传进来的指向头结点的这个指针是否为NULL,如果头结点指向NULL,这是一个空链表
{
printf("\nThis list is null!\n");
goto end;//4直接跳转到end这个地方
}
p1=head;//p1指向head
while(p1->num!=num&&p1->next!=NULL)//5p1指向链表的第一个结点,这个结点的学号不等于我们要删除的学号的时候;p1的next还不指向NULL,也就是p1还不是最后一个结点的时候(&&操作两个只要一个为0,则就为0)
{
p2=p1;//6p1的值就给了p2
p1=p1->next;//7p1就指向了下一个数据(下一个结点)(这个时候第一个数据是p2指向了,第二个数据是p1指向了)
}//直到不满足上述while的两个条件才会退出循环
if(num==p1->num)//8p1指向的学号p1->num,等于我们要删除的学号num的时候就应该要做删除操作了
{
if(p1==head)//8还需要再验证一下p1这个时候是不是头结点
{
head=p1->next;//是的话,就必须把头结点给p1的下一个,然后才把p1给删了,(你不能直接把头给切了,如果把头给切了拿什么来返回)(头应该指向p1的下一任,然后才能把头给切掉)
}
else//如果不是头结点,(p2是指向了p1的上一任)
{
p2->next=p1->next;//把p1的next赋值给p1的next(比如p2是指向A结点,P1是结点,p1的next是C结点,因为p1的next就是B指向C(B->C),p2的next就是A指向B(A->B),就是将C给了A,就是直接把B给删除掉了(A->C))(next是一个指针,指向下一个地点的指针)
}
printf("\nDelete No:%d succeed!\n",num);
n=n-1;//n是作为一个全局变量用来记录链表的数据数
}
else
{
printf("%d not been found!\n",num)
}
end://直接结束,因为空链表没有办法删除
return head;
}
结果:
链表的插入:
对链表的插入是指将一个结点插入到一个已有的链表中。
为了做到正确插入,必须解决两个问题:
(1)怎样找到插入位置;
(2)怎样实现插入。
我们可以先用指针变量p0指向待插入的结点,p1指向第一个结点。将p0->num于p1->num相比较,如果p0->num大于p1->num,此时将p1后移,并使p2指向刚才p1所指的结点。 (大前提num在列表中都 是按照大小存放的)
(下边abc是一种插入方法,02在01之后,03之前,所以插入位置肯定在03之前,找到插入位置,告诉这个链表我要进去,所以链表先把03给甩了,这时候p1就指向了03,p2->next还是指向03,之后开始脱节(p1在指向下一个位置之前,我们要用p2要保存一下p1原来的位置,p1才可以放心的走),将p2->next指向了02(p2),这时候p0->next指向了p1也就是我们的03,这样就做好了交接工作,把他给链了进来。(这时候我们就看到了主要发生变化的就是他们的next指针,所以我们在链表中的第三个数据他的next变量非常重要,它记录了下一个结点的位置,只要改变他的位置就可以成功的发生删除和插入操作)(在中间比较麻烦,先断开,第一个指向它p0,他再指向第三个)
d是一种插入方法,(就是插入的在最前面,就是在他的头结点之前,那么我们的head就指向了它p0。他的next就指向了我们原来的第一个结点)
e是一种插入方法(要插入的位置刚好在最后的,要插入的在最后,那么必须使它的p0->next指向null)
流程图:
首先p1指向head,p0指向我们要输入的一个结构,如果链表是空表的话,head指向p0,p0->指向NULL。不是空表我们就来判断
代码:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define LEM sizeof(struct student)//student结构的大小
struct student *create();//创建链表
struct student *del(struct student*head,int num); //del函数用于删除结点, *head即链表的头指针, num是要删除的结点num。
struct student *insert(struct student *head,struct student *stu_2);// 第一个参数需要被插入的链表// 第二个参数待插入的结构的地址
void print(struct student *head);//打印链表
struct student
{
int num;
float score;
struct student *next;
};
int n;//全局变量,用来记录存放了多少数据
void main()
{
struct student *stu,*p,stu_2;
int n;
stu=creat();
p=stu;
print(p);
printf("\nPlease input the num to delete:")
scanf("%d",&n);
print(del(p,n));
printf("\nPlease input the num to insert:")
scanf("%d",&stu_2.num);
printf("Please input the score: ");
scanf("%f", &stu_2.score);
p = insert(stu, &stu_2);//用p指向了他返回的头指针
print( p );//把它给打印出来//其实也可以不用p直接嵌套调用print(insert(stu, &stu_2));
printf("\n\n");
system("pause");
}
struct student *creat()
{
struct student *head;
struct student *p1, *p2;
p1 = p2 = (struct student *)malloc(LEN); // LEN是student结构的大小
printf("Please enter the num :");
scanf("%d", &p1->num);
printf("Please enter the score :");
scanf("%f", &p1->score);
head = NULL;
n = 0;
while( p1->num )
{
n++;
if( 1 == n )
{
head = p1;
}
else
{
p2->next = p1;
}
p2 = p1;
p1 = (struct student *)malloc(LEN);
printf("\nPlease enter the num :");
scanf("%d", &p1->num);
printf("Please enter the score :");
scanf("%f", &p1->score);
}
p2->next = NULL;
return head;
}
//打印
void print(struct student *head)
{
struct student *p;
printf("\nThere are %d records!\n\n", n);
p = head;
if( head )
{
do
{
printf("学号为 %d 的成绩是: %f\n", p->num, p->score);
p = p->next;
}while( p );
}
}
struct student *del( struct student *head, int num)
{
struct student *p1, *p2;
if( NULL == head )
{
printf("\nThis list is null!\n");
goto end;
}
p1 = head;
while( p1->num != num && p1->next != NULL)
{
p2 = p1;
p1 = p1->next;
}
if( num == p1->num )
{
if( p1 == head )
{
head = p1->next;
}
else
{
p2->next = p1->next;
}
printf("Delete No: %d succeed!\n", num);
n = n-1;
}
else
{
printf("%d not been found!\n", num);
}
end:
return head;
}
//插入
struct student *insert(struct student *head,struct student *stu_2)
{
struct student *p0,*p1,*p2;
p1=head;
p0=stu_2;
if(NULL==head)
{
head=p0;
p0->next=NULL;
}
else
{
while((p0->num > p1->num)&&(p1->next!=NULL))//意思就是待插入的102大于101,或者//两种情况退出while((第一种p0->num < p1->num)达到了插入的条件,)(第二种p0跑到了最后表的结尾)
{
p2=p1;//p2用来保存p1的结点(因为我们插入需要用到p1的上一个结点,所以用p2来保存)
p1=p1->next;//p1跳槽指向下一个节点(其实这个while循环是在为中间插入做前期工作)
}
if(p0->num <= p1->num)//小于的话又有两种情况:
{
if(head==p1)//p1是头结点,插入头部
{
head=p0;
}
else//普通情况,插入中间
{
p2->next=p0;//p2是刚才p1的上一个结点的值,p2的next指向了p0
}
p0->next=p1;//p0的next指向了p1
}
else//p0的num最大,插入到末尾
{
p1->next=p0;
p0->next=NULL
}
}
n=n+1;//由于插入,所以增加了一位数据成员进入链表中。
return head;//返回插入链表的头指针(后再通过print调用)
}
//还可以改写,需要多次插入
最后实现插入程序并制作一个学生成家管理系统。