参考主要是谭向强的那本《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