C语言程序设计实训:基于二叉树的学生信息管理系统

 

    1. main函数:以菜单形式将各项功能提供给用户,根据用户的

选择,调用相应的函数。

    1. 建立TreeNode* readStudentsFromFile函数,返回二叉树的根节点,从文件中输入学生信息,中序遍历输出学生信息。
    2. 建立compareStudent函数,按照平均成绩升序排序。
    3. 按照某门课成绩升序排序。
    4. 查找平均分最大最小。
    5. 查找某门课成绩最大最小。
    6. 建立TreeNode* modifyStudentScore函数,返回二叉树的根节点,实现修改学生成绩的操作。
    7. 建立exportStudentInfoToFile函数,保存学生数据到文件。
    8. 建立TreeNode* deleteNode函数,返回二叉树的根节点,删除学生数据。

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 学生信息结构体
struct Student {
    char num[15];     // 学号
    char name[15];    // 姓名
    char major[10];   // 专业(computer, software, network)
    int classNo;      // 班级(1-2)
    int score[3];     // 3门课的成绩(0-2)
};

// 二叉树结构体节点定义
struct TreeNode {
    struct Student data;      // 数据域,存储学生信息
    struct TreeNode *left;    // 左子树指针
    struct TreeNode *right;   // 右子树指针
};

// 插入学生信息到二叉树
struct TreeNode* insertStudent(struct TreeNode* root, struct Student student) {
    // 如果根为空,创建新节点作为根
    if (root == NULL) {
        struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
        newNode->data = student;
        newNode->left = NULL;
        newNode->right = NULL;
        return newNode;
    }

    // 根据学号比较决定插入左子树或右子树
    if (strcmp(student.num, root->data.num) < 0) {
        root->left = insertStudent(root->left, student);
    } else {
        root->right = insertStudent(root->right, student);
    }

    return root;
}

// 从文件读取学生信息并插入到二叉树
struct TreeNode* readStudentsFromFile(struct TreeNode* root, const char* filename) {
    FILE *fp;
    fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("Error opening file");
        return root;
    }

    // 读取文件中的每一行,解析学生信息并插入二叉树
    char line[100];
    while (fgets(line, sizeof(line), fp)) {
        struct Student student;
        sscanf(line, "%s %s %s %d %d %d %d", student.num, student.name, student.major,
               &student.classNo, &student.score[0], &student.score[1], &student.score[2]);
        root = insertStudent(root, student);
    }

    fclose(fp);
    return root;
}

// 中序遍历二叉树(用于测试),二叉树是一条线
void inorderTraversal(struct TreeNode* root) {
    if (root != NULL) {
        inorderTraversal(root->left);
        printf("学号:%s, 姓名:%s, 专业:%s, 班级:%d, 成绩:%d, %d, %d\n",
               root->data.num, root->data.name, root->data.major,
               root->data.classNo, root->data.score[0], root->data.score[1], root->data.score[2]);
        inorderTraversal(root->right);
    }
}

// 计算学生的平均成绩
double calculateAverageScore(struct Student student) {
    double sum = 0.0;
    for (int i = 0; i < 3; ++i) {
        sum += student.score[i];
    }
    return sum / 3.0;
}

// 中序遍历二叉树,将学生信息节点按照平均成绩存入数组
void inorderTraversal(struct TreeNode *root, struct Student *sortedStudents, int *index) {
    if (root != NULL) {
        inorderTraversal(root->left, sortedStudents, index);
        sortedStudents[*index] = root->data;
        (*index)++;
        inorderTraversal(root->right, sortedStudents, index);
    }
}

// 比较函数,用于qsort排序
int compareStudents(const void *a, const void *b) {
    struct Student *studentA = (struct Student *)a;
    struct Student *studentB = (struct Student *)b;
    double avgA = calculateAverageScore(*studentA);
    double avgB = calculateAverageScore(*studentB);

    if (avgA < avgB) return -1;
    else if (avgA > avgB) return 1;
    else return 0;
}

// 比较函数,用于qsort排序
int compareStudents0(const void *a, const void *b) {
    struct Student *studentA = (struct Student *)a;
    struct Student *studentB = (struct Student *)b;

    // 按第一门课程成绩升序排序
    return studentA->score[0] - studentB->score[0];
}

// 比较函数,用于qsort排序
int compareStudents1(const void *a, const void *b) {
    struct Student *studentA = (struct Student *)a;
    struct Student *studentB = (struct Student *)b;

    // 按第一门课程成绩升序排序
    return studentA->score[1] - studentB->score[1];
}

// 比较函数,用于qsort排序
int compareStudents2(const void *a, const void *b) {
    struct Student *studentA = (struct Student *)a;
    struct Student *studentB = (struct Student *)b;

    // 按第一门课程成绩升序排序
    return studentA->score[2] - studentB->score[2];
}

// 函数声明:修改二叉树上某个学生的特定一门课程的成绩
struct TreeNode* modifyStudentScore(struct TreeNode *root, const char* targetNum, int courseIndex, int newScore) {
    // 如果根节点为空,直接返回
    if (root == NULL) {
        return NULL;
    }

    // 在左子树中查找目标学生
    root->left = modifyStudentScore(root->left, targetNum, courseIndex, newScore);

    // 如果当前节点的学号与目标学号匹配,则更新特定课程的成绩
    if (strcmp(root->data.num, targetNum) == 0) {
        // 更新特定课程的成绩
        if (courseIndex >= 0 && courseIndex < 3) {
            root->data.score[courseIndex] = newScore;
        } else {
            printf("错误:课程索引超出范围!\n");
        }
    }

    // 在右子树中查找目标学生
    root->right = modifyStudentScore(root->right, targetNum, courseIndex, newScore);

    return root;
}

// 中序遍历二叉树并将学生信息输出到文件
void inorderTraversalToFile(struct TreeNode *root, FILE *fp) {
    if (root != NULL) {
        inorderTraversalToFile(root->left, fp);
        fprintf(fp, "学号:%s,姓名:%s,专业:%s,班级:%d,成绩:%d %d %d\n",
                root->data.num, root->data.name, root->data.major, root->data.classNo,
                root->data.score[0], root->data.score[1], root->data.score[2]);
        inorderTraversalToFile(root->right, fp);
    }
}

// 将学生信息输出到文件
void exportStudentInfoToFile(struct TreeNode *root, const char *filename) {
    FILE *fp = fopen(filename, "w"); // 打开文件以写入模式

    if (fp == NULL) {
        perror("无法打开文件");
        return;
    }

    // 写入学生信息到文件
    inorderTraversalToFile(root, fp);

    // 关闭文件
    fclose(fp);
}

// 查找并删除指定学号的节点
struct TreeNode* deleteNode(struct TreeNode* root, const char* num) {
    if (root == NULL) {
        printf("未找到要删除的学号为 %s 的学生信息。\n", num);
        return root;
    }

    // 寻找要删除的节点
    if (strcmp(num, root->data.num) < 0) {
        root->left = deleteNode(root->left, num);
    } else if (strcmp(num, root->data.num) > 0) {
        root->right = deleteNode(root->right, num);
    } else { // 找到了要删除的节点
        // 情况1: 节点没有子节点或者只有一个子节点
        if (root->left == NULL) {
            struct TreeNode* temp = root->right;
            free(root);
            return temp;
        } else if (root->right == NULL) {
            struct TreeNode* temp = root->left;
            free(root);
            return temp;
        }

        // 情况2: 节点有两个子节点,找到右子树中最小的节点来替换当前节点
        struct TreeNode* temp = root->right;
        while (temp->left != NULL) {
            temp = temp->left;
        }

        // 用右子树中最小节点的值替换当前节点的值
        root->data = temp->data;

        // 删除右子树中最小节点
        root->right = deleteNode(root->right, temp->data.num);
    }

    return root;
}




int main() {
    struct TreeNode* root = NULL;
    int count=10;
    int zaijian;
    int cishu=5;
    char r[20];
    while (1) {
        printf("请输入用户swh的密码:\n");
        scanf("%s", r);
        while (cishu != 0) {
            if (strcmp(r, "swh040527") == 0) {
                printf("登陆成功!\n");
                cishu=1;
                break;
            } else {
                if (cishu == 0) {
                    printf("登录失败,请等待30s后重新登陆!\n");
                    break;
                }
                cishu--;
                printf("密码错误,请重新登录\n");
                printf("您还有%d次机会\n", cishu);
                printf("请输入用户swh的密码:\n");
                scanf("%s", r);

            }
        }
        if (cishu == 0) {
            printf("登录失败,请等待30s后重新登陆!\n");
            break;
        }
        break;
    }
    while(1){
        int a;
        printf("-----------------------------------------------------------\n");
        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("请输入序号:\n");
        scanf("%d",&a);
        if ((a < 1) || (a > 17))
            printf("你的输入有误,请重新输入\n");
        switch (a){
            case 1:{
                // 从文件中读取学生信息并插入二叉树
                root = readStudentsFromFile(root, "studentInit.txt");
                // 中序遍历打印二叉树
                printf("中序遍历二叉树结果:\n");
                inorderTraversal(root);
                break;
            }

            case 2:{
                int n=count;
                struct Student sortedStudents[n];
                int index = 0;

                // 中序遍历二叉树,将学生信息按照平均成绩存入sortedStudents数组
                inorderTraversal(root, sortedStudents, &index);

                // 使用qsort函数对sortedStudents数组按照平均成绩进行排序
                qsort(sortedStudents, n, sizeof(struct Student), compareStudents);

                // 输出排序后的学生信息
                printf("按照平均成绩排序后的学生信息:\n");
                for (int i = 0; i < n; ++i) {
                    printf("姓名:%s,学号:%s,专业:%s,班级:%d,平均成绩:%.2f\n",
                           sortedStudents[i].name, sortedStudents[i].num,
                           sortedStudents[i].major, sortedStudents[i].classNo,
                           calculateAverageScore(sortedStudents[i]));
                }
                break;
            }
            case 3:{
                // 假设有足够大的数组存储学生信息
                struct Student students[100]; // 假设最多存储100个学生信息
                int index = 0;
                int xuanze=0;
                printf("选择你要排序的课程序号012:\n");
                scanf("%d",&xuanze);
                // 中序遍历二叉树,将学生信息存储到数组中
                inorderTraversal(root, students, &index);

                // 计算实际存储的学生数量
                int n = index;
                if(xuanze==0){
                    // 使用qsort函数对学生数组按第0门课程成绩排序
                    qsort(students, n, sizeof(struct Student), compareStudents0);

                }
                if(xuanze==1){
                    // 使用qsort函数对学生数组按第1门课程成绩排序
                    qsort(students, n, sizeof(struct Student), compareStudents1);
                }
                if(xuanze==2){
                    // 使用qsort函数对学生数组按第2门课程成绩排序
                    qsort(students, n, sizeof(struct Student), compareStudents2);
                }
                // 使用qsort函数对学生数组按第0门课程成绩排序
                //qsort(students, n, sizeof(struct Student), compareStudents0);

                // 输出排序后的学生信息
                printf("按第一门课程成绩升序排序后的学生信息:\n");
                for (int i = 0; i < n; ++i) {
                    printf("姓名:%s,学号:%s,专业:%s,班级:%d,第一门课成绩:%d\n",
                           students[i].name, students[i].num,
                           students[i].major, students[i].classNo,
                           students[i].score[xuanze]);
                }

                break;
            }

            case 4:{
                // 假设有足够大的数组存储学生信息
                struct Student students[100]; // 假设最多存储100个学生信息
                int index = 0;

                // 中序遍历二叉树,将学生信息存储到数组中
                inorderTraversal(root, students, &index);

                // 计算实际存储的学生数量
                int n = index;
                int xuanze=0;
                printf("输出最大成绩0还是最小成绩1:\n");
                scanf("%d",&xuanze);
                // 找到平均分最大的学生
                if(xuanze==0) {
                    float maxAverage = -1.0; // 初始化一个负数,确保能找到比所有平均分都低的分数
                    struct Student *maxStudent = NULL;

                    for (int i = 0; i < n; ++i) {
                        float avg = calculateAverageScore(students[i]);
                        if (avg > maxAverage) {
                            maxAverage = avg;
                            maxStudent = &students[i];
                        }
                    }

                    // 输出平均分最大的学生信息
                    printf("平均分最大的学生信息:\n");
                    printf("姓名:%s,学号:%s,专业:%s,班级:%d\n",
                           maxStudent->name, maxStudent->num,
                           maxStudent->major, maxStudent->classNo);
                    printf("平均分:%.2f\n", maxAverage);
                }
                if(xuanze==1){
                    float maxAverage = 101; // 初始化一个负数,确保能找到比所有平均分都低的分数
                    struct Student *maxStudent = NULL;

                    for (int i = 0; i < n; ++i) {
                        float avg = calculateAverageScore(students[i]);
                        if (avg < maxAverage) {
                            maxAverage = avg;
                            maxStudent = &students[i];
                        }
                    }

                    // 输出平均分最大的学生信息
                    printf("平均分最小的学生信息:\n");
                    printf("姓名:%s,学号:%s,专业:%s,班级:%d\n",
                           maxStudent->name, maxStudent->num,
                           maxStudent->major, maxStudent->classNo);
                    printf("平均分:%.2f\n", maxAverage);
                }
                break;
            }

            case 5:{
                int xuanze1,xuanze2;
                printf("最高成绩0还是最低成绩1:\n");
                scanf("%d",&xuanze1);
                printf("第几门012:\n");
                scanf("%d",&xuanze2);
                // 假设有足够大的数组存储学生信息
                struct Student students[100]; // 假设最多存储100个学生信息
                int index = 0;

                // 中序遍历二叉树,将学生信息存储到数组中
                inorderTraversal(root, students, &index);

                // 计算实际存储的学生数量
                int n = index;
                if(xuanze1==0) {
                    // 找到某门课成绩最高的学生
                    int maxScoreIndex = -1;
                    int maxScore = -1; // 假设成绩不会低于0

                    // 假设要找第一门课的最高成绩
                    for (int i = 0; i < n; ++i) {
                        if (students[i].score[xuanze2] > maxScore) {
                            maxScore = students[i].score[xuanze2];
                            maxScoreIndex = i;
                        }
                    }

                    // 输出某门课成绩最高的学生信息
                    printf("第%d门课成绩最高的学生信息:\n",xuanze2);
                    printf("姓名:%s,学号:%s,专业:%s,班级:%d\n",
                           students[maxScoreIndex].name, students[maxScoreIndex].num,
                           students[maxScoreIndex].major, students[maxScoreIndex].classNo);
                    printf("第%d门课最高成绩:%d\n",xuanze2, maxScore);
                }
                if(xuanze1==1) {
                    // 找到某门课成绩最高的学生
                    int maxScoreIndex = 101;
                    int maxScore = 101; // 假设成绩不会低于0

                    // 假设要找第一门课的最高成绩
                    for (int i = 0; i < n; ++i) {
                        if (students[i].score[xuanze2] < maxScore) {
                            maxScore = students[i].score[xuanze2];
                            maxScoreIndex = i;
                        }
                    }

                    // 输出某门课成绩最高的学生信息
                    printf("第%d门课成绩最低的学生信息:\n",xuanze2);
                    printf("姓名:%s,学号:%s,专业:%s,班级:%d\n",
                           students[maxScoreIndex].name, students[maxScoreIndex].num,
                           students[maxScoreIndex].major, students[maxScoreIndex].classNo);
                    printf("第%d门课最低成绩:%d\n",xuanze2, maxScore);
                }
                break;
            }

            case 6:{
                int xuanze,fenshu;
                char targetNum[20];
                // 假设有一个已经构建好的二叉树,根节点为 root

                // 新的成绩
                //int newScore = 100; // 假设新的成绩
                //int courseIndex = 1; // 假设要修改第二门课程的成绩
                printf("请输入要修改成绩的学生学号:\n");
                scanf("%s",targetNum);
                printf("修改第几门成绩012:\n");
                scanf("%d",&xuanze);
                printf("修改为多少分:\n");
                scanf("%d",&fenshu);
                // 要修改的学号
                //const char* targetNum = "2220221235"; // 假设目标学号

                // 修改学生信息
                root = modifyStudentScore(root, targetNum, xuanze, fenshu);

                // 输出修改后的二叉树信息
                printf("修改后的学生信息:\n");
                inorderTraversal(root);

                break;
            }
            case 7:{

                exportStudentInfoToFile(root, "studentx.txt");

                printf("学生信息已成功导出到 studentx.txt 文件中。\n");
                break;
            }

            case 8:{
                char shan[20];
                printf("请输入你要删除学生数据的学号:\n");
                // 删除学号为 "1002" 的学生信息
                scanf("%s",shan);
                root = deleteNode(root, shan);

                printf("删除后的二叉树中的学生信息:\n");
                inorderTraversal(root);
                break;
            }
            case 9:{
                zaijian=886;
                printf("欢迎下次使用!\n");
            }
        }
        if(zaijian==886){
            break;
        }
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值