一段充满血与泪的代码(链表的一些基本操作)
别问为什么充满血与泪,问就是我菜
以下代码主要是通过学习B站UP主C3程序猿课程学来的。
#include <stdio.h> #include <stdlib.h> #include<string.h> #define N 100 void tillinsert(int id,char *name,float score);//尾部插入结点 void print();//输出链表全部信息 void headinsert(int id,char *name,float score);//头部插入结点 struct student* search(int idtemp); void nodeinsert(int id,char *name,float score,int idtemp);//从一个结点前插入 void deletenode(int id);//删除结点 void deletehead();//删除头结点 void deletetill(); //删除尾结点 //创建结构体 struct student{ int id; char name[N]; float score; struct student* next; }; //初始化头尾结点 struct student* head=NULL; struct student* end=NULL; //主函数 int main(){ int id; char name[N]; float score; printf("请输入学生总数:\n"); int i,n; scanf("%d",&n); printf("请按顺序输入学生的id,姓名,分数,中间空格隔开\n"); for(i=1;i<=n;i++){ scanf("%d",&id); scanf("%s",name); scanf("%f",&score); tillinsert(id,name,score); } print(); printf("从头部插入结点,请输入数据:\n"); scanf("%d",&id); scanf("%s",name); scanf("%f",&score); headinsert(id,name,score); print(); printf("从尾部插入结点,请输入数据:\n"); scanf("%d",&id); scanf("%s",name); scanf("%f",&score); tillinsert(id,name,score); print(); printf("输入一个结点的id,查询该结点内容:\n"); int idtemp; scanf("%d",&idtemp); struct student* pp; pp=search(idtemp); printf("id:%d name:%s score:%f\n",pp->id,pp->name,pp->score); printf("从任意一个前插入新的结点,请输入该结点中id:\n"); scanf("%d",&idtemp); printf("请输入要插入结点中的数据:\n"); scanf("%d",&id); scanf("%s",name); scanf("%f",&score); nodeinsert(id,name,score,idtemp); print(); printf("请输入所要删除的结点的id:\n"); scanf("%d",&id); deletenode(id); print(); } //从尾部插入结点 void tillinsert(int id,char *name,float score){ //创建结点 开辟空间 struct student* p1=(struct student*)malloc(sizeof(struct student)); //参量赋值 //由于字符数组的特殊性,采用strcpy函数来赋值 p1->id=id; strcpy(p1->name,name); p1->score=score; p1->next=NULL; if(head==NULL||end==NULL){ head=p1; end=p1; } else{ end->next=p1; end=p1; } } //输出链表信息 void print(){ struct student* p=head; printf("该链表的信息目前为:\n"); while(p!=NULL){ printf("id:%d name:%s score:%f\n",p->id,p->name,p->score); p=p->next; } } //头部插入结点 void headinsert(int id,char *name,float score){ struct student* p2=(struct student*)malloc(sizeof(struct student)); p2->id=id; strcpy(p2->name,name); p2->score=score; if(head==NULL||end==NULL){ head=p2; end=p2; } else{ p2->next=head; head=p2; } } //查询指定结点,返回值为指针类型 struct student* search(int idtemp){ struct student*ptemp=head; while(ptemp!=NULL){ if(ptemp->id==idtemp){ return ptemp; } ptemp=ptemp->next; } if(ptemp==NULL){ printf("未找到指定结点\n"); return NULL; } } //从一个结点前插入新的结点 idtemp为所要插入的结点对应的id void nodeinsert(int id,char *name,float score,int idtemp){ struct student* p3=head; //特殊情况:对应id为头结点的id,即刚好要插入头结点前 if(p3->id==idtemp){ headinsert(id,name,score); return; } //非特殊情况:先遍历查找指定位置 while(p3->next!=NULL){ if(p3->next->id==idtemp){ break; } p3=p3->next; } //如若没有查找到指定结点 if(p3->next==NULL){ printf("该结点不存在\n"); return; } //已经查找到指定结点,建立要插入的结点并赋值 struct student* ptemp=(struct student*)malloc(sizeof(struct student)); ptemp->id=id; strcpy(ptemp->name,name); ptemp->score=score; //连接结点 ptemp->next=p3->next; p3->next=ptemp; } void deletehead(){ struct student* ptemp=head; head=head->next; free(ptemp); } void deletetill(){ //第一种情况下,只有一个结点 if(head==end){ free(head); head=NULL; end=NULL; } else{ //找到尾巴前一个结点 struct student* ptemp=head;//ptemp为尾巴前面的一个结点 struct student* pt=end;//pt为尾结点 while(ptemp->next!=end){ ptemp=ptemp->next; } end=ptemp;//尾巴前移 free(pt);//释放旧的尾结点 end->next=NULL; } } //删除结点 void deletenode(int id){ //如果链表为空 if(head==NULL){ printf("该链表为空\n"); return; } //查询是否有该结点 struct student* p=head; while(p!=NULL){ if(p->id==id){ break; } p=p->next; } if(p==NULL){ printf("未找到此结点\n"); return; } //第一种情况 只有一个结点 if(head==end){ deletehead(); } //有两个结点,所要删除的结点为头尾结点中的一个(主要是删除头尾结点的算法不同,因此需要分情况讨论) else if(head->next==end){ if(head->id==id){ deletehead(); } else{ deletetill(); } } //有多个结点 else{ //依旧判断删除头尾 if(p==head){ deletehead(); } else if(p==end){ deletetill(); } else{ //非特殊情况,需要找到所删除结点的前一个结点 struct student* ptemp=head; while(ptemp->next!=p){ ptemp=ptemp->next; } ptemp->next=p->next; free(p); } } }
人生如逆旅,我亦是行人