首页 > 其他分享 >C语言———链表的创建、循环删除和循环插入系统

C语言———链表的创建、循环删除和循环插入系统

时间:2022-11-19 23:01:57浏览次数:81  
标签:p0 p1 struct 结点 C语言 链表 循环 student

  参考主要是谭向强的那本《C程序设计》和B站上的小甲鱼的视频,视频的话B站上搜就有,就不把链接放上了。

背景:      

   前两天在学习C语言的过程中又重新学习了一下链表的知识。之前也做过一部分相应C语言链表的知识总结相关可参考这些链表P->NEXT=Q->NEXT,Q->NEXT=P,Q=P;的一些解释C语言链表逆序问题(附图解)

  这次算是记录一下自己编写的程序,用于加深一下关于链表的理解。

程序分析:

  1、链表创建操作

  下图为链表创建操作的流程图,

  1、首先采用动态链表的方法生成一个新节点,让p1、p2指向这个新节点;

  2、然后读入要创建的数据给p1所指向的结点;

  3、头指针先赋值为NULL,并建立一个n值使其等于0,用于后面的判断是否是第一个节点;

  4、用while建立一个循环语句,当读入的p1->num!=0进入循环,否则跳出循环。

    4.1、首先进行n++操作,用于判断是否是头结点。

    4.2、当n=1时,令头指针指向p1(这时相当于讲p1所指的结点作为第一个结点),如果n!=1时,令p2->next=p1(相当于讲p1所指的结点放在了p2的next中)

    4.3、令p2=p1(是让p2移到表尾,虽然刚开始p1和p2的地址指向是一样的,但后面p1又重新开辟了结点,所以需要这一步,如果单纯的对p1只赋值一次那么p2=p1);

    4.4、对p1重新开辟新节点,如果不进行开辟的话,会重用地址。

    4.5、然后再对其进行重新赋值。

  5、将p2的结点赋值为NULL,结束链表。

  2、链表删除操作

  1、首先需要判断链表是否为空,若是空的则输出空表(在本篇中得添加了插入操作,若是空的话会执行插入操作),否则执行删除操作。

  2、重新定义两个链表p1,p2,将头结点赋给p1,p2用于后面的操作;

  3、找到要删除的对象所在链表的位置,方法是采用一个while循环,判断条件是p1->num!=num以及p1所指的结点不是表尾结点)

  4、找到位置后,判断是否是要删除的结点:

    4.1、如果是需判断是否是头结点

      4.1.1、是头结点就删除头结点。操作为head=p1->next。

      4.1.2、不是头结点就删除一个结点,操作为p2->next=p1->next;

    4.2、如果不是要删除的结点就输出找不到要删除的数据。

  3、链表插入操作

     该部分在程序中有更详细的说明可参考程序中/*插入操作*/struct student *inside(struct student *head,struct student *p0),其中插入操作中得head指的是原链表,p0指的是待插入的链表。

 C语言程序:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<malloc.h>
  5 
  6 struct student
  7 {
  8     long num;               //学号
  9     float score;           //成绩
 10     struct student *next;
 11 };
 12 int n;
 13 //struct student *creat(struct student *head)
 14 /*插入操作*/
 15 struct student *inside(struct student *head,struct student *p0)
 16 {
 17     struct student *p1,*p2;
 18     //    p2=(struct student *)malloc(sizeof(struct student));
 19     p1=head;        //使P1指向要操作的链表
 20     if(p1==NULL)               //head链表为空的情况,将p0所指的结点作为唯一的结点
 21     {
 22         head=p0;               //指向要插入的链表数据
 23         p0->next=NULL;
 24     }   
 25     else                       //不为空的情况
 26     {
 27         while(p0->num>p1->num&&p1->next!=NULL)    //while循环主要是找到p0要插入的位置
 28         {
 29             p2=p1;                
 30             p1=p1->next;          
 31         }
 32         if(p0->num<=p1->num)
 33         {
 34             if(p1==head)          //插入到头结点
 35             {
 36                 head=p0;          //头结点指向p0
 37                 p0->next=p1;      //p0的地址指向p1
 38             }
 39             else                  //插入到中间
 40             {
 41                 p2->next=p0;      //p2的地址指向p0
 42                 p0->next=p1;      //p0的地址指向p1
 43             }
 44         }
 45         else                     //插入到末尾
 46         {
 47             p1->next=p0;         //p1的地址指向p0 
 48             p0->next=NULL;       //p0的地址为空
 49         }
 50     }
 51     return head;
 52 }
 53 
 54 struct student *creat()
 55 {
 56     n=0;
 57     struct student *p1,*p2,*head;
 58     p1=p2=(struct student *)malloc(sizeof(struct student));            //p1、p2指向第一个开辟的动态结点
 59     head=NULL;               //初始化头结点为空
 60     printf("输入第1个学生的学号和成绩(学号为0创建结束):\n");
 61     scanf("%ld %f",&p1->num,&p1->score);     
 62     while(p1->num!=0)
 63     {
 64         n++;
 65         if(n==1)      //把p1所指的结点作为第一个结点
 66         {
 67             head=p1;
 68         }
 69         else         //把p1所指的结点链接到表未
 70         {
 71             p2->next=p1;
 72         }
 73         p2=p1;       //相当于把p1中的值全部给了p2,也就相当于p2移动到了p1
 74         p1=(struct student *)malloc(sizeof(struct student));    //p1从新指向开辟的新的动态结点
 75         printf("输入第%d学生的学号和成绩(学号为0创建结束):\n",n+1);                   
 76         scanf("%ld %f",&p1->num,&p1->score);
 77         
 78     }
 79     p2->next=NULL;       
 80     return head;
 81     
 82 }
 83 struct student *del(struct student *head,long num)
 84 {
 85     struct student *p3,*p4;
 86     //    p1=(struct stude*)malloc(sizeof(struct student));
 87     p3=head;                     //指向头结点  
 88     if(p3==NULL)
 89     {
 90         printf("输入错误!\n");           
 91     }
 92     while(p3->next!=NULL&&p3->num!=num)      //处理p3->num!=num以及p3所指的结点不是表尾结点
 93     {
 94         p4=p3;                               //p4后移一个位置
 95         p3=p3->next;                         //p3后移一个位置    
 96     }
 97     if(p3->num==num)                         //p3是要删除的结点
 98     {
 99         if(p3==head)                         //要删除p3点是头结点
100         {
101             head=p3->next;                   //head后移一个位置
102         }
103         else
104         {
105             p4->next=p3->next;               //
106         }
107     }
108     else
109     {
110         printf("找不到信息!\n");
111     }
112     return head;
113 }
114 
115 void print(struct student *head)
116 {
117     struct student *p;
118     p=head;           //让p指向第一个结点
119     if(head!=NULL)
120     {
121         do
122         {
123             printf("学号:%ld,成绩:%f\n",p->num,p->score);      
124             p=p->next;                                            //p指向下一个结点
125         }while(p!=NULL);
126     }
127     else
128     {
129         printf("链表为空!\n");
130     }
131 }
132 
133 void main()
134 {
135     int n,m;
136 
137     struct student *pt,*pt_del,*p0,*p1,*pt_inside;
138     p0=(struct student *)malloc(sizeof(struct student ));     //要在链表中插入的结构体
139     p1=(struct student *)malloc(sizeof(struct student ));     //要在链表中删除的结构体
140     pt=creat();                                                //
141     if(pt!=NULL)
142     {
143         printf("输出创建的所有学号和成绩(创建成功):\n");
144         print(pt);
145         printf("请选择插入和删除操作:插入输入1,删除输入2:\n");
146         scanf("%d",&n);
147         if(n==2)
148         {
149         /*链表删除循环操作*/
150             printf("输入要删除的学号(当学号为0时结束删除操作):\n");
151             scanf("%ld",&p1->num);
152             while(p1->num!=0)
153             {
154                 pt_del=del(pt,p1->num);
155                 pt=pt_del;                    //使pt指向删除操作过后的链表,方便下面进行循环删除
156                 printf("输入要删除的学号(当学号为0时结束删除操作):\n");
157                 p1=(struct student *)malloc(sizeof(struct student *));         //开辟一个新单元,若不进行该步操作会导致报错
158                 scanf("%ld",&p1->num);
159             }
160 //            printf("输出删除后的所有学号和成绩(当学号为0时结束删除操作):\n");
161 //            print(pt);
162             printf("是否要执行插入操作:执行输入1 ,不执行输入2 \n");
163             scanf("%d",&m);
164 //            m=getchar();
165             if(m==1)
166             {
167                 printf("输入要插入的学号和成绩(当学号为0时结束插入操作):\n");   
168                 scanf("%ld%f",&p0->num,&p0->score);
169                 while(p0->num!=0)
170                 {
171                     pt_inside=inside(pt,p0);
172                     pt=pt_inside;               //使pt指向插入操作过后的链表,方便下面进行循环插入
173                     p0=(struct student *)malloc(sizeof(struct student *));       //开辟新单元,若不进行该步操作,会陷入一个死循环。原因是一个地址被重复使用
174                     printf("输入要插入的学号和成绩(当学号为0时结束插入操作):\n");   
175                     scanf("%ld%f",&p0->num,&p0->score);
176                 }
177                 printf("输出插入后的所有学号和成绩:\n");
178                 print(pt_inside);
179             }
180             else
181             {
182                 printf("输出删除后的所有学号和成绩(当学号为0时结束删除操作):\n");
183                 print(pt);
184             }
185         }
186         else
187         {
188             printf("创建失败,请插入学号和成绩(当学号为0时结束插入操作):\n");
189             scanf("%ld%f",&p0->num,&p0->score);        
190             while(p0->num!=0)         
191             {
192                 pt_inside=inside(pt,p0);
193                 pt=pt_inside;
194                 p0=(struct student *)malloc(sizeof(struct student));
195                 printf("输入要插入的学号和成绩(当学号为0时结束插入操作):\n");
196                 scanf("%ld%f",&p0->num,&p0->score);
197             }
198             printf("输出插入后的所有学号和成绩:\n");
199             print(pt_inside);
200         }
201     }
202     else
203     {
204         /*循环执行插入操作*/
205         printf("创建失败,输入要插入的学号和成绩(当学号为0时结束插入操作):\n");
206         scanf("%ld%f",&p0->num,&p0->score);        
207         while(p0->num!=0)         
208         {
209             pt_inside=inside(pt,p0);
210             pt=pt_inside;
211             p0=(struct student *)malloc(sizeof(struct student));
212             printf("输入要插入的学号和成绩(当学号为0时结束插入操作):\n");
213             scanf("%ld%f",&p0->num,&p0->score);
214         }
215         printf("输出插入后的所有学号和成绩:\n");
216         print(pt_inside);
217     }
218     
219 }
220 
221 //1、注意虽然逻辑上一个是链表中的节点,一个是结构体变量,是两个东西,但是在内存中存在一个地址中。
222 ///在重新接收数据时stu_2的内容和链表的第二个内容被同时覆盖,第二次运行插入函数通过比较,新节点插入在旧1、2节点间。
223 //作为链表的第二个节点,放入链表.
224 
225 //2、新进来的节点和第一次插入的节点是一个节点,导致两个节点相同,新进来的节点指向上次插入的节点,
226 //也就是它本身从而不断指向本身,死循环。
227 
228 //3、关键在于p0->next=p1这里,p0=p1.导致p0自己指向自己

 

 

标签:p0,p1,struct,结点,C语言,链表,循环,student
From: https://www.cnblogs.com/sbb-first-blog/p/16841871.html

相关文章