C语言:随笔9--链表

接上篇: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调用)
}

//还可以改写,需要多次插入

最后实现插入程序并制作一个学生成家管理系统。

猜你喜欢

转载自blog.csdn.net/m0_37957160/article/details/108724896
今日推荐