【用C语言描述数据结构】课程设计:歌手比赛系统(1)

文末附有全部代码哦💖💖

文末附有全部代码哦~

一、具体问题

1.问题描述:

设计一个简单的歌手比赛绩管理程序,对一次歌手比赛的成绩进行管理,使用链表实现,基本的设计要求如下(不限于此要求):

(1)输入每个选手的数据包括编号、姓名、十个评委的成绩,根据输入计算出总成绩和平均成绩(去掉最高分,去掉最低分)。

(2)显示主菜单如下:

  • 1.选手数据输入
  • 2.评委打分
  • 3.成绩排序
  • 4.数据查询
  • 5.追加选手数据
  • 6.删除选手数据
  • 7.修改选手数据
  • 8.输出全部选手信息
  • 9.写入数据文件
  • 10.退出系统

    2.问题来源

    当下,无论是校园内还是在社会生活中,经常会举行一些歌手演唱比赛,在信息化的时代里,不会再像以前那样用笔和纸记录比赛的赛况,歌手比赛系统应运而生。歌手比赛系统包含了一切歌手演唱比赛需要的功能,歌手信息的输入,评委打分,成绩排序等功能操作简单高效,可以完成很多繁琐的工作,完全可以满足一切歌手比赛的需求。开发此系统只为方便歌手演唱比赛的举办。

    3.解决手段

    歌手比赛系统是一个可以储存多个比赛选手信息的系统,主要采用链表来实现存储信息的需求,使用头插法来输入数据,通过选手编号来实现评委打分,成绩排序,数据查询,追加选手数据,删除选手信息,修改选手信息,输出全部选手信息,写入数据文件等功能。

    4.应用前景

    在信息技术迅速发展的今天,网络对于大多数人已经不再陌生,网络在人们的工作、学习和生活中发挥着不可替代的作用,大大提高了人们生产生活效率。歌手比赛系统是信息技术在人们工作生活中应用的代表,该系统完成评委打分,成绩排序,数据查询,追加选手数据,删除选手信息,修改选手信息,输出全部选手信息,写入数据文件等功能,这些功能可以让评委们在歌手比赛结算时时更加方便快捷。同时,该系统也可以应用到其他比赛当中,使比赛更加方便快捷。

    二、需求分析

    1.功能需求分析

    歌手比赛系统是我们为了方便进行歌手比赛而开发的一套系统,该系统的主要目的是实现选手的信息分析,该系统具有评委打分,成绩排序,数据查询,追加选手数据,删除选手信息,修改选手信息,输出全部选手信息,写入数据文件等功能。同时,歌手比赛系统基于c语言编译的源程序,其调用函数根据所需要模块进行引用,再编写好之后,要对程序进行相应的调试,以验证程序的正确性和可用性。调试及测试时,通过相应信息,充分证明程序的可行性,同时本程序具有很高的逻辑性和严密性。

    2.系统功能模块图

    该程序的系统功能模块图如下图所示。

    3.数据结构定义

    typedef struct Node {
        int id;//编号
        char name[MAXSIZE];//姓名
        float grade[NUMBER];//评委评分
        float sum;//总分
    float average;//平均分
    struct Node \*next;//指针域
    } S;//结构体定义为S
    //各函数定义
    void menu(); //菜单函数 
    S \*create();//创建链表函数 
    void print(S \*);//输出链表函数 
    void insert(S \*);//插入节点函数 
    void del(S \*);//删除节点函数
    void update(S \*);
    void search(S \*);//查找节点函数
    void sort(S \*);//节点排序函数 
    void save(S \*);
    void giveScore(S \*);
    

    三、系统设计

    1.主要函数表

    2.功能流程图

    (1)添加选手信息

    如下图所示:

    (2)修改选手信息

    如下图所示:

    (3)删除选手信息

    如下图所示:

    四、代码测试

    1.主函数

    //主函数
    int main() {
        S \*head;
        int n, a = 1;//n用来控制选择操作类型,a控制循环,以-1终止
        while (a > 0) {
            menu();//显示菜单
            printf("请输入操作数:");
            scanf("%d", &n);//选择操作
            switch (n)//各操作数字对应菜单数字,通过n确定操作类型
            {
                //创建结点,输入选手数据
                case 1:
                    head = create();
                    break;
                    //评委打分
                case 2:
                    if (head == NULL) {
                        printf("链表为空,请先执行1操作!\n");
                        break;
                    }
                    giveScore(head);
                    break;
                    //排序
                case 3:
                    if (head == NULL) {
                        printf("链表为空,请先执行1操作!\n");
                        break;
                    }
                    sort(head);
                    break;
                    //查询
                case 4:
                    if (head == NULL) {
                        printf("链表为空,请先执行1操作!\n");
                        break;
                    }
                    search(head);
                    break;
                    //追加数据
                case 5:
                    if (head == NULL) {
                        printf("链表为空,请先执行1操作!\n");
                        break;
                    }
                    insert(head);
                    break;
                    //删除
                case 6:
                    if (head == NULL) {
                        printf("链表为空,请先执行1操作!\n");
                        break;
                    }
                    del(head);
                    break;
                    //修改数据
                case 7:
                    if (head == NULL) {
                        printf("链表为空,请先执行1操作!\n");
                        break;
                    }
                    update(head);
                    break;
                    //输出全部选手信息
                case 8:
                    if (head == NULL) {
                        printf("链表为空,请先执行1操作!\n");
                        break;
                    }
                    print(head);
                    break;
                    //写入文件
                case 9:
                    if (head == NULL) {
                        printf("链表为空,请先执行1操作!\n");
                        break;
                    }
                    save(head);
                    break;
                    //退出系统
                case 0:
                    exit(0);
                    break;
                default:
                    printf("退出系统");
                    a = -1;//跳出循环条件
                    break;
            }
        }
        return 0;
    }
    

    2.菜单模块

    //菜单模块直接显示 
    void menu() {
        printf("==============================\n");
        printf("=========请选择操作============\n");
        printf("========1.输入选手数据=========\n");
        printf("========2.评委打分============\n");
        printf("========3.成绩排序============\n");
        printf("========4.数据查询============\n");
        printf("========5.追加选手数据=========\n");
        printf("========6.删除选手信息=========\n");
        printf("========7.修改选手信息=========\n");
        printf("========8.输出全部选手信息======\n");
        printf("========9.写入数据文件=========\n");
        printf("========0.退出系统============\n");
        printf("=============================\n");
    }
    
    • 运行结果如下:

      3.输入选手数据模块

      //1.输入选手数据
      S \*create() {
          S \*head, \*p, \*q;//定义指针
          int i;
          head = (S \*) malloc(sizeof(S));//头节点开辟空间
          head->average = 0;//置空头节点的average成员
          head->next = NULL;//置空头节点的指针域
          q = head;//q指针记录头节点的地址
          p = head->next;//p指针记录头节点的指针域的地址
          printf("请输入选手编号和姓名(编号为0则表示停止):\n");
          int id;
          printf("请输入选手id(输入0退出):\n");
          scanf("%d", &id);
          while (id != 0)//输入选手编号输入为零停止循环
          {
              p = (S \*) malloc(sizeof(S));//p指针开辟空间
              p->id = id;
              printf("请输入选手姓名:\n");
              scanf("%s", p->name);
              for (i = 0; i < NUMBER; i++) {
                  p->grade[i] = 0;
              }
              p->sum = 0;
              p->average = 0;
              p->next = NULL;//置空p节点的指针域
              q->next = p;//p,q节点连接
              q = p;//q指针后移
              printf("请输入选手id(输入0退出):\n");
              scanf("%d", &id);
          }
          return head;//返回链表的起始地址
      }
      
      • 运行结果如下:

        4.评委打分模块

        //2.评委打分
        void giveScore(S \*head) {
            //定义指针
            S \*p;
            p = head->next;
            float max, min;
            while (p != NULL) {
                if (p->grade[0] != 0) {
                    p = p->next;
                    continue;
                }
                printf("请十位评为给编号为%d的选手打分:\n", p->id);
                p->sum = 0;
                for (int i = 0; i < NUMBER; i++) {
                    printf("请第%d位评委打分:", i);
                    scanf("%f", &p->grade[i]);
                    p->sum += p->grade[i];
                }
                printf("\n");
                min = max = p->grade[0];
                for (int i = 0; i < NUMBER; i++) {
                    if (p->grade[i] > max)
                        max = p->grade[i];
                    if (p->grade[i] < min)
                        min = p->grade[i];
                }
                p->average = (p->sum - max - min) / 8;
                p = p->next;
            }
        }
        
        • 运行结果如下:

          5.按照平均成绩排序 – 采用冒泡排序,交换节点

          //3.按照平均成绩排序 -- 采用冒泡排序,交换节点
          void sort(S \*head) {
              S \*p, \*pre, \*temp, \*tail;
              tail = NULL;
          // 算法的核心部分,节点交换
              while (head->next != tail) {
                  pre = head;
                  p = head->next;
                  while (p->next != tail) {
                      if (p->average < p->next->average) {
                          temp = p->next;
                          pre->next = p->next;
                          p->next = p->next->next;
                          pre->next->next = p;
                          p = temp;
                      }
                      // 节点后移
                      p = p->next;
                      pre = pre->next;
                  }
                  tail = p;
              }
          }
          

          6.数据查询模块

          //4.根据id查找节点模块
          void search(S \*head) {
              S \*p;//定义指针
              int id;//定义b用于输入查找编号
              printf("请输入要查找的选手编号:");
              //输入查找编号
              scanf("%d", &id);
              p = head->next;
              while (p != NULL) {
                  if (p->id == id)//判断是否找到选手编号
                  {
                      //为真时,输出信息
                      printf("编号\t姓名\t\t\t\t\t十位评委的成绩\t\t\t\t\t总成绩\t平均成绩\n");
                      printf("%d %s %.2f%.2f%.2f%.2f%.2f%.2f%.2f%.2f%.2f%.2f %.2f %.2f\n", p->id, p->name, p->grade[0],
                             p->grade[1], p->grade[2], p->grade[3], p->grade[4], p->grade[5], p->grade[6], p->grade[7],
                             p->grade[8], p->grade[9], p->sum, p->average);
                      break;
                  } else
                      //为假时
                      p = p->next;//指针后移
              }
              if (p == NULL)//查找到最后一个节点还未查到要的编号时,输出ERROR INPUT
                  printf("输入的选手编号错误\n");
          }
          
          • 运行结果如下:

            7.追加选手数据模块

            //5.追加节点模块(可多个插入)
            void insert(S \*head) {
                int i, id, flag = 1;//flag实现判断指针是否到达最后一个节点
                S \*p, \*q, \*r;    //定义指针便于插入操作
                p = head;
                printf("请输入选手信息:\n");
                printf("请输入选手id(输入0退出):\n");
                scanf("%d", &id);
                while (id != 0)//输入编号不为零时循环,以零终止,可实现多个插入
                {
                    r = (S \*) malloc(sizeof(S));//为r开辟空间
                    r->next = NULL;//置空r的指针域
                    //输入相关数据,并计算相关数据
                    r->id = id;
                    printf("请输入选手姓名:\n");
                    scanf("%s", r->name);
                    r->sum = 0;
                    r->average = 0;
                    for (i = 0; i < NUMBER; i++) {
                        r->grade[i] = 0;
                    }
                    while (p->next != NULL) {
                        p = p->next;
                    }
                    p->next = r;
                    printf("请输入选手id(输入0退出):\n");
                    scanf("%d", &id);
                }
            }
            
            • 运行结果如下:

              8.删除选手信息模块

              //6.删除节点模块
              void del(S \*head) {
                  S \*p, \*q;//定义指针
                  int b;//用于输入编号查找删除
                  p = head;//p记录头节点的地址
                  q = head->next;//q记录头节点的指针域的地址
                  printf("请输入要删除选手的id:");
                  //输入编号
                  scanf("%d", &b);
                  while (q != NULL)//q不为空时执行循环
                  {
                      if (q->id == b)//判断是否找到输入的编号
                          //为真时
                      {
                          p->next = q->next;//断开q节点
                          free(q);//释放q节点neicun
                          q = NULL;    //置空q指针防止出现野指针
                      } else {
                          //判断为假时
                          p = p->next;//p指针后移
                          q = q->next;//q指针后移
                      }
                  }
                  if (p == NULL)//当查找到最后一个节点还未查到要删除的编号时,输出ERROR INPUT
                      printf("输入的选手id不存在!\n");
              }
              
              • 运行结果如下:

                9.修改选手信息模块

                //修改选手信息
                void update(S \*head) {
                    S \*p, \*q, \*new;//定义指针
                    int id;//用于输入编号查找删除
                    float min = 999, max = 0;
                    p = head;//p记录头节点的地址
                    q = head->next;//q记录头节点的指针域的地址
                    printf("请输入要修改的选手id:");
                    //输入编号
                    scanf("%d", &id);
                    while (q != NULL)//q不为空时执行循环
                    {
                        //判断是否找到输入的编号
                        if (q->id == id) {
                            new = (S \*) malloc(sizeof(S));
                            printf("请输入%d号选手的新成绩:", q->id);
                            new->id = q->id;
                            strcpy(new->name, q->name);
                            new->sum = 0;
                            new->average = 0;
                            for (int i = 0; i < NUMBER; ++i) {
                                scanf("%f", &new->grade[i]);
                                new->sum += new->grade[i];
                                if (new->grade[i] > max) {
                                    max = new->grade[i];
                                }
                                if (new->grade[i] < min) {
                                    min = new->grade[i];
                                }
                            }
                            new->average = (new->sum - max - min) / (NUMBER - 2);
                            new->next = q->next;//断开q节点
                            p->next = new;
                            free(q);//释放q节点
                            q = NULL;    //置空q指针防止出现野指针
                        } else {
                            //判断为假时
                            p = p->next;//p指针后移
                            q = q->next;//q指针后移
                        }
                    }
                    if (p == NULL)//当查找到最后一个节点还未查到要修改的编号时
                        printf("输入的选手id不存在!\n");
                }
                
                • 运行结果如下:

                  10.输出全部选手信息模块

                  //7.输出全部选手信息
                  void print(S \*head) {
                      int i;
                      S \*p = head->next;
                      printf("编号\t姓名\t总成绩\t平均成绩\t\t\t\t\t十位评委的成绩\t\t\t\t\n");
                      while (p)//当p不为空的时候执行
                      {
                          printf("%-d\t%-s\t%-.2f\t%-.2f\t", p->id, p->name, p->sum, p->average);
                          for (i = 0; i < NUMBER; i++)
                              printf("%-6.2f\t", p->grade[i]);
                          printf("\n");
                          p = p->next;//指针后移
                      }
                  }
                  
                  • 运行结果如下:

                    11.写入数据文件(记得修改写入文件地址)

                    //8.写入数据文件
                    void save(S \*head) {
                        S \*p;
                        p = head->next;
                        FILE \*fp;
                        if ((fp = fopen("C:\\Users\\zhuxuanyu\\Desktop\\file.txt", "wt")) == NULL) {
                            printf("打开写入文件fle.txt失败\n");
                            return;
                        }
                        while (p) {
                            fprintf(fp, "编号:%-d\t 姓名:%-s\t 总成绩:%-.2f\t 平均成绩:%-.2f\t 评委打分:", p->id, p->name, p->sum,
                                    p->average);
                            for (int i = 0; i < NUMBER; ++i) {
                                fprintf(fp, "%-.2f\t", p->grade[i]);
                            }
                            fprintf(fp, "\n");
                            p = p->next;
                        }
                        fclose(fp);
                    }
                    

                    五、完整代码

                    #include #include #include //创建结构体及其成员 
                    #define MAXSIZE 20
                    #define NUMBER 10
                    typedef struct Node {
                        int id;//编号
                        char name[MAXSIZE];//姓名
                        float grade[NUMBER];//评委评分
                        float sum;//总分
                        float average;//平均分
                        struct Node \*next;//指针域
                    } S;//结构体定义为S
                    //各函数定义
                    void menu(); //菜单函数 
                    S \*create();//创建链表函数 
                    void print(S \*);//输出链表函数 
                    void insert(S \*);//插入节点函数 
                    void del(S \*);//删除节点函数
                    void update(S \*);
                    void search(S \*);//查找节点函数
                    void sort(S \*);//节点排序函数 
                    void save(S \*);
                    void giveScore(S \*);
                    //主函数
                    int main() {
                        S \*head;
                        int n, a = 1;//n用来控制选择操作类型,a控制循环,以-1终止
                    ![img](https://img-blog.csdnimg.cn/img_convert/ee864a13836278a5a3af92094dd81490.png)
                    ![img](https://img-blog.csdnimg.cn/img_convert/dde37275d9aa96dd1074cff79b42f432.png)
                    **网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
                    **[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**
                    **一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
                    oid menu(); //菜单函数 
                    S \*create();//创建链表函数 
                    void print(S \*);//输出链表函数 
                    void insert(S \*);//插入节点函数 
                    void del(S \*);//删除节点函数
                    void update(S \*);
                    void search(S \*);//查找节点函数
                    void sort(S \*);//节点排序函数 
                    void save(S \*);
                    void giveScore(S \*);
                    //主函数
                    int main() {
                        S \*head;
                        int n, a = 1;//n用来控制选择操作类型,a控制循环,以-1终止
                    [外链图片转存中...(img-CJfvvSnZ-1714457783062)]
                    [外链图片转存中...(img-eAeh9wQm-1714457783063)]
                    **网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
                    **[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**
                    **一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**