直播提醒⏰:2小时手撸一个学生管理系统!

“ 关注hahaCoder 获取最新资讯”

直播提醒

我将在2021.11.7下午2:30进行一次直播,手把手教大家2小时内通过C语言编写一个学生管理系统,包括学生信息的增删改查等8个功能模块,其所用到的知识点包括指针、结构体、链表等,届时欢迎各位小伙伴们来我的直播间围观!

fece8a0a82ebd6543459b58235681e7d.png

概述

本文是《C语言程序设计》系列教程的最后一篇文章,我将结合指针结构体链表来完成一个学生管理系统,其功能包括 建立学生信息顺序输出学生信息逆序输出学生信息插入学生信息删除学生信息修改学生信息查找学生信息 以及 清空学生信息

「注」:本案例通过单向链表来实现。

链表概述

  • 链表由节点组成,每个节点中包含两个域,分别是数据域指针域,本案例中数据域通过结构体实现,用来存储学生的姓名、学号、年龄;指针域用来存储下一个节点的地址。

  • 链表是一种线性表,线性表包含两种存储方式:顺序存储(数组)和链式存储(链表)。

365f5e047f00eb2ee817552fec507f8d.png

功能拆分

  • 建立链表

  • 遍历链表(顺序遍历、逆序遍历)

  • 插入节点(头节点、尾节点、任意节点)

  • 删除节点(头节点、尾节点、任意节点)

  • 修改节点信息

  • 查找节点

  • 清空链表

e6441c84746d95b46d6bc1e9b6fb8a16.png

功能1:建立学生信息

思路:通过malloc函数申请内存空间,并逐个添加链表节点,注意,单链表中最后一个节点的指针域为空,即next指向的值为NULL

struct student *createList(){
  struct student *head;//头节点
  struct student *p1;//开辟新节点
  struct student *p2;//与p1连接
  int num1;
  char name1[20];
  int age1;
  head = NULL;
  int count = 1;
  
  printf("请输入第1个学生的学号、姓名、年龄(用空格分隔):");
  scanf("%d%s%d",&num1,&name1,&age1);
  while(age1>0){
    p1 = (struct student*)malloc(sizeof(struct student));
    p1->num = num1;
    strcpy(p1->name,name1);
    p1->age = age1;
    p1->next = NULL;
    if(head == NULL){
      head = p1;
    }else{
      p2->next = p1;
    }
    p2 = p1;
    printf("请输入第%d个学生的学号、姓名、年龄(用空格分隔):",++count);
    scanf("%d%s%d",&num1,&name1,&age1);
  }
  return head;
}
功能2:顺序输出学生信息

思路:对单链表进行遍历操作。

void displayList(struct student *head){
  struct student *p;
  int n = 0;
  if(head!=NULL){
    printf("顺序输出链表中学生信息如下:\n");
    for(p=head;p!=NULL;p=p->next){
      printf("学号:%-6d 姓名:%-20s 年龄:%-6.1d\n",p->num,p->name,p->age);
      n++;
    }
    printf("学生总数:%d\n",n);
  }else{
    printf("空链表!\n");
  }
}
功能3:逆序输出学生信息

思路:

  1. 借助递归

  2. 借助栈

  3. 修改单链表指向

29bd7c9cce8c5c6eb07fddd78016845d.png

struct student *reverseList(struct student *head){
  /*
    1. 借助递归
  */
  /*
  struct student *p;
  p = head;
  if(p!=NULL){
    reverseList(p->next);
    printf("学号:%-6d 姓名:%-20s 年龄:%-6.1d\n",p->num,p->name,p->age);
  }
  */
  
  /*
    2. 借助栈
  */
  struct student *p;
  p = head;
  stack<int> s;
  while(p!=NULL){
    s.push(p->num);
    p = p->next;
  }
  while(!s.empty()){
    p = head;
    while(s.top()!=p->num){
      p = p->next;
    }
    if(s.top()==p->num){
      printf("学号:%-6d 姓名:%-20s 年龄:%-6.1d\n",p->num,p->name,p->age);
    }
    s.pop();
  }
  return head;
   
  /*
    3. 改变单链表指针指向
    改变指针指向后,原链表也会被修改
  */
  
  /*
  struct student *pre;
  struct student *post;
  struct student *p;
  pre = NULL;
  post = NULL;
  while(head!=NULL){
    post = head->next;
    head->next = pre;
    pre = head;
    head = post;
  }
  return pre;
  */
  
}
功能4:插入学生信息

思路:

  • 插入头节点

899eda3a90121448ffe1bb964cd5a1dc.png

  • 插入任意节点

ee91763f0268d4c390ffb2f7441798ae.png

  • 插入尾节点

70a07750280c26ef48168749ff932b91.png

struct student *insertNodes(struct student *head){
  struct student *p;//待插入节点
  struct student *p1;//待插入节点的前驱节点
  struct student *p2;//待插入节点的后继节点
  p2 = head;
  p = (struct student *)malloc(sizeof(struct student));
  printf("请输入要加入学生的学号、姓名、年龄:");
  scanf("%d%s%d",&p->num,&p->name,&p->age);
  if(head == NULL){ //若为空链表,则相当于创建一个新节点
    head = p;
    p->next = NULL;
  }else{
    while(p->num > p2->num&&p2->next!=NULL){ //查找待插入的位置
      p1 = p2;
      p2 = p2->next;
    }
    if(p->num < p2->num){ //头节点和中间任意节点的插入
      if(p2 == head){ //头节点
        head = p;
        p->next = p2;
      }else{ // 中间任意节点
        p1->next = p;
        p->next = p2;
      }
    }else{//尾节点的插入
      p2->next = p;
      p->next = NULL;
    }
  }
   return head;
}
功能5:删除学生信息

思路:

  • 删除头节点

89cba25664a743178fea46b961f85453.png

  • 删除任意节点

3f39a07902cb945b768f20738f6a5c95.png

  • 删除尾节点

9bf36fa448194b9682ae2f3284f26a4b.png

struct student *deleteNodes(struct student *head){
  
  struct student *p1;
  struct student *p2;
  
  int num2;//要删除学生的学号
  printf("请输入要删除学生的学号:");
  scanf("%d",&num2);
  
  if(head == NULL){
    printf("链表为空\n");
    return head;
  }
  p2 = head;
  
  while(num2!=p2->num&&p2->next!=NULL){ //查找要删除的节点
    p1 = p2;
    p2 = p2->next;
  }
  
  if(num2 == p2->num){
    if(p2 == head){ //要删除的是头节点
      head = p2->next;
    }else{ //其他节点
      p1->next = p2->next;
    }
    free(p2);
    printf("删除了学号为%d的学生信息!\n",num2);
  }else{
    printf("该生不存在!\n");
  }
  return head;
}
功能6:修改学生信息

思路:查找并修改

void modify_student_info(struct student *head){
  struct student *p;
  int num;
  char name[20];
  int age;
  printf("请输入您要修改学生的学号:");
  scanf("%d",&num);
  p = head;
  if(head!=NULL){
    while(p->num!=num&&p->next!=NULL){
      p = p->next;
    }
    if(p->num==num){
      printf("请输入您要更改后的信息:\n");
      scanf("%d%s%d",&num,&name,&age);
      p->num = num;
      strcpy(p->name,name);
      p->age = age;
    }else{
      printf("没有找到学号为%d的学生信息,请确认学号信息是否正确!\n");
    }
  }else{
    printf("空链表\n");
  } 
}
功能7:查找学生信息

思路:查找并遍历

void search_student_info(struct student *head){
  struct student *p;
  int num;//要查找对应学生的学号信息
  printf("请输入要查找学生的学号:");
  scanf("%d",&num);
  p = head;
  //非空链表的情况下
  if(head != NULL){
    while(p->num!=num&&p->next!=NULL){
      p=p->next;
    }
    //不满足while循环的第一个条件
    if(p->num==num){
      printf("你所查找的学号为%d的学生信息如下:\n",num);
      printf("学号:%-6d 姓名:%-20s 年龄:%-6.1d\n",p->num,p->name,p->age);
    }else{
      //不满足while循环的最后一个条件
      printf("没有找到学号为%d的学生信息,请确认学号是否正确!\n",num);
    }
  }else{//空链表的情况
    printf("空链表!");
  }
}
功能8:清空学生信息

思路:清空或销毁链表

7898428a913eb235c624e08bcd9ba542.png

struct student *destroyList(struct student *head){
    struct student *p,*q;
    if(head==NULL){
        printf("空链表!\n");
    }
    p = head->next;
    while(p!=NULL){
        q = p->next;
        free(p);
        p = q;
    }
    printf("信息删除完毕!\n");
    head = NULL;
    return head;
}

项目进阶

  • 单向循环链表

c925d5492916595e62ff5c7b2dc848ff.png

  • 双向链表

945e85b45b14b825992520ce874eb352.png

  • 双向循环链表

407294d1660387dee7d847995d9de36c.png

获取课件

2021.11.7下午2:30直播完成后,我会将课件上传至百度网盘,大家在微信公众号后台回复「C语言直播」获取链接,即可下载!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hahaCoderX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值