-
- main函数:以菜单形式将各项功能提供给用户,根据用户的
选择,调用相应的函数。
-
- 建立TreeNode* readStudentsFromFile函数,返回二叉树的根节点,从文件中输入学生信息,中序遍历输出学生信息。
- 建立compareStudent函数,按照平均成绩升序排序。
- 按照某门课成绩升序排序。
- 查找平均分最大最小。
- 查找某门课成绩最大最小。
- 建立TreeNode* modifyStudentScore函数,返回二叉树的根节点,实现修改学生成绩的操作。
- 建立exportStudentInfoToFile函数,保存学生数据到文件。
- 建立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;
}