一段充满血与泪的代码(链表的一些基本操作)

别问为什么充满血与泪,问就是我菜

以下代码主要是通过学习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("请输入学生总数:
");
    int i,n;
    scanf("%d",&n);
    printf("请按顺序输入学生的id,姓名,分数,中间空格隔开
");
    for(i=1;i<=n;i++){
        scanf("%d",&id);
        scanf("%s",name);
        scanf("%f",&score);
        tillinsert(id,name,score);
    }
    print();
    printf("从头部插入结点,请输入数据:
");
    scanf("%d",&id);
    scanf("%s",name);
    scanf("%f",&score);
    headinsert(id,name,score);
    print();
    printf("从尾部插入结点,请输入数据:
");
    scanf("%d",&id);
    scanf("%s",name);
    scanf("%f",&score); 
    tillinsert(id,name,score);
    print();
    printf("输入一个结点的id,查询该结点内容:
");
    int idtemp;
    scanf("%d",&idtemp);
    struct student* pp;
    pp=search(idtemp);
    printf("id:%d   name:%s   score:%f
",pp->id,pp->name,pp->score);
    printf("从任意一个前插入新的结点,请输入该结点中id:
");
    scanf("%d",&idtemp);
    printf("请输入要插入结点中的数据:
");
    scanf("%d",&id);
    scanf("%s",name);
    scanf("%f",&score);
    nodeinsert(id,name,score,idtemp);
    print();
    printf("请输入所要删除的结点的id:
");    
    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("该链表的信息目前为:
");
    while(p!=NULL){
        printf("id:%d   name:%s   score:%f
",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("未找到指定结点
");
      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("该结点不存在
");
        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("该链表为空
");
        return;
    }
    //查询是否有该结点 
    struct student* p=head;
    while(p!=NULL){
        if(p->id==id){
            break;
        }
        p=p->next; 
    }
    if(p==NULL){
        printf("未找到此结点
");
        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);
        }
    }  
} 
人生如逆旅,我亦是行人
原文地址:https://www.cnblogs.com/sz2003/p/14139275.html