数据结构与算法——附加作业一:成绩管理系统

《数据结构与算法》附加作业一报告:成绩管理系统

一、目的和要求(需求分析)

建立数据库,并对信息进行插入、修改、删除与查找。

具体要求:1. 提供用户界面提示,方便操作

2. 登记学生基本信息及各门功课成绩

      3. 修改学生基本信息及各门功课成绩

      4. 删除某学生或某班所有学生的基本信息或各门功课成绩

      5. 查找某学生的基本信息或全部成绩信息

二、程序设计的基本思想,原理和算法描述

1. 数据结构:建立一个带有头结点和尾结点的双向链表。

原理:该链表需要经常访问某个节点的前驱和后继,故使用双向链表。

2. 利用for循环语句完成链表元素的输入、删除、修改、查找。

    原理:用for循环从前往后遍历链表,找到要插入、删除或修改元素的结点位置,对其进行相关操作。 

3. 输入/输出设计:通过用户界面提示,引导用户管理信息,完成操作。

4. 符号名说明:变量名太多,使用英文单词直译方便理解。

三、调试和运行程序过程中产生的问题及采取的措施

1. 问题:一开始觉得无从下手,有好多操作需要完成。

采取措施:结合平时生活中数据管理需要进行的操作,在草稿纸上写下自己的程序需要满足的操作要求。在确定要求后,开始动手,更有方向与目标。

2. 问题:程序中变量名太多且程序代码很长,写代码时十分混乱。

采取措施:采用了分模块设计的思路,先将主函数内需要的操作码好,再去定义调用的各函数。 

3. 问题:没有考虑到原本数据不存在的特殊情况。

采取措施:改善代码,通过在代码中加入异常检测解决了该问题。

四、源程序及注释

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


//将所有链表都定义为双向链表,方便操作 
//科目链表ADT
typedef struct subNode{ 
	//科目链表节点
    char name[10]; // 科目名称
    int score; // 成绩
    
    struct subNode *next; // 下一个节点
    struct subNode *previous; // 前一个节点
} *subPosition;
typedef struct {
	//科目链表结构体
    subPosition head;
    subPosition tail;
} subList;
subList createSubList();
int subListEmpty(subList l);
void insertSub(subPosition p, subList *l, char *name, int score);
void delSub(subPosition p, subList *l);
subPosition findSub(subList l, char *name);
void clearSubList(subList *l);
void printSubList(subList l);
void destroySubList(subList *l);


//学生链表ADT
typedef struct stuNode {
    //学生链表节点
    long id; // 学号
    char name[10]; //姓名
    int sex; //性别,1为男,0为女
    int age; //年龄
    long telephone; //电话
    subList subjects; //课程链表

    struct stuNode *next; // 下一个节点
    struct stuNode *previous; // 前一个节点
} *stuPosition;
typedef struct {
    //学生链表结构体
    stuPosition head;
    stuPosition tail;
} stuList;
stuList createStuList();
int stuListEmpty(stuList l);
void insertStu(stuPosition p, stuList *l, long id, char *name, int sex, int age, long telephone);
void delStu(stuPosition p, stuList *l);
stuPosition findStu(stuList l, long id);
void clearStuList(stuList *l);
void printStuList(stuList l);
void destroyStuList(stuList *l);


//班级链表ADT
typedef struct classNode {
    //班级链表节点
    int classId; // 班级编号
    stuList students; // 学生链表

    struct classNode *next; // 下一个节点
    struct classNode *previous; // 前一个节点
} *classPosition;
typedef struct {
    // 班级链表结构体
    classPosition head;
    classPosition tail;
} classList;
classList createClassList();
int classListEmpty(classList l);
void insertClass(classPosition p, classList *l, int classId);
void delClass(classPosition p, classList *l);
classPosition findClass(classList l, int classId);
void clearClassList(classList *l);
void printClassList(classList l);
void destroyClassList(classList *l);


// 用户界面
void showMainInterface();


int main() 
{
    classList classes = createClassList(); // 初始化班级链表
    int flag = 1; // 判断用户是否选择退出程序。若退出,值为0;否则为1
	showMainInterface(); //显示主菜单
	
    while(flag) 
	{
        printf("\n请输入操作代号:");
        int optNo; // 操作代号
        scanf("%d", &optNo);
        switch (optNo) 
		{ //根据用户输入的操作代号选择对应的操作
            case 1: 
			{ //查看所有班级
                if (classListEmpty(classes)) printf("\n当前还未添加任何班级!\n");
                else printClassList(classes);
                break;
            }
            case 2: 
			{ //查看某个班级内的所有学生
                printf("请输入班级编号:");
                int classId;
                scanf("%d", &classId);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n未找到该班级!\n");
                else if (stuListEmpty(class->students)) printf("\n该班级内还未添加任何学生!\n");
                else printStuList(class->students);
                break;
            }
            case 3: 
			{ //查看某个学生的基本信息
                printf("请输入学生所在的班级编号和学号,中间用空格分隔:");
                int classId;
                long stuId;
                scanf("%d%ld", &classId, &stuId);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n未找到该班级!\n");
                else 
				{
                    stuPosition stu = findStu(class->students, stuId);
                    if (!stu) printf("\n未找到该学生!\n");
                    else 
					{
                        printf("\n学号:%ld", stu->id);
                        printf(" 姓名:%s", stu->name);
                        printf(" 性别:%s", stu->sex == 1 ? "male" : "female");
                        printf(" 年龄:%d", stu->age);
                        printf(" 电话:%ld\n", stu->telephone);
                    }
                }
                break;
            }
            case 4: 
			{ //查看某个学生的所有成绩
                printf("请输入学生所在的班级和学号,中间用空格分隔:");
                int classId;
                long stuId;
                scanf("%d%ld", &classId, &stuId);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n未找到该班级!\n");
                else 
				{
                    stuPosition stu = findStu(class->students, stuId);
                    if (!stu) printf("\n未找到该学生!\n");
                    else if (subListEmpty(stu->subjects)) printf("\n该学生还未添加任何成绩!\n");
                    else printSubList(stu->subjects);
                }
                break;
            }
            case 5: 
			{ //插入新班级
                printf("请输入班级编号:");
                int classId;
                scanf("%d", &classId);
                classPosition class = findClass(classes, classId);
                if (class) printf("\n当前班级已存在!\n");
                else insertClass(classes.tail, &classes, classId);
                break;
            }
            case 6: 
			{ //插入新学生
                printf("请输入学生所在的班级编号、学号、姓名(英文)、性别(male/female)、年龄和电话,中间用空格分隔:\n");
                int classId, age;
                long stuId, telephone;
                char name[10], sex[10];
                scanf("%d%ld%s%s%d%ld", &classId, &stuId, name, sex, &age, &telephone);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n该班级不存在!\n");
                else 
				{
                    stuPosition stu = findStu(class->students, stuId);
                    if (stu) printf("\n当前学生已存在!\n");
                    else insertStu(class->students.tail, &class->students,stuId, name, !strcmp(sex, "male") ? 1 : 0, age, telephone);
                }
                break;
            }
            case 7: 
			{ //插入新成绩
                printf("请输入成绩所属学生的班级编号、学号、成绩对应的科目名称(英文)和成绩,中间用空格分隔:\n");
                int classId, score;
                long stuId;
                char subName[10];
                scanf("%d%ld%s%d", &classId, &stuId, subName, &score);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n该班级不存在!\n");
                else 
				{
                    stuPosition stu = findStu(class->students, stuId);
                    if (!stu) printf("\n该学号不存在!\n");
                    else 
					{
                        subPosition sub = findSub(stu->subjects, subName);
                        if (sub) printf("\n当前成绩已存在!\n");
                        else insertSub(stu->subjects.tail, &stu->subjects, subName, score);
                    }
                }
                break;
            }
            case 8: 
			{ //删除某个班级
                printf("请输入要删除的班级编号:");
                int classId;
                scanf("%d", &classId);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n该班级不存在!\n");
                else delClass(class, &classes);
                break;
            }
            case 9: 
			{ //删除所有班级
                clearClassList(&classes);
                break;
            }
            case 10: 
			{ //删除某个学生
                printf("请输入要删除的学生所在的班级编号和学号,中间用空格分隔:");
                int classId;
                long stuId;
                scanf("%d%ld", &classId, &stuId);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n找不到该班级!\n");
                else 
				{
                    stuPosition stu = findStu(class->students, stuId);
                    if (!stu) printf("\n找不到该学生!\n");
                    else delStu(stu, &class->students);
                }
                break;
            }
            case 11: 
			{ //删除某个班级内的所有学生
                printf("请输入要删除所有学生的班级编号:");
                int classId;
                scanf("%d", &classId);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n找不到该班级!\n");
                else clearStuList(&class->students);
                break;
            }
            case 12: 
			{ //删除某学生的某门成绩 
                printf("请输入要删除的成绩所属学生的班级编号、学号和对应的科目名称(英文),中间用空格分隔:");
                int classId;
                long stuId;
                char subName[10];
                scanf("%d%ld%s", &classId, &stuId, subName);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n找不到该班级!\n");
                else 
				{
                    stuPosition stu = findStu(class->students, stuId);
                    if (!stu) printf("\n找不到该学生!\n");
                    else 
					{
                        subPosition sub = findSub(stu->subjects, subName);
                        if (!sub) printf("\n找不到该成绩!\n");
                        else delSub(sub, &stu->subjects);
                    }
                }
                break;
            }
            case 13: 
			{ //删除某学生的所有成绩
                printf("请输入要删除所有成绩的学生所在的班级编号和学号,中间用空格分隔:");
                int classId;
                long stuId;
                scanf("%d%ld", &classId, &stuId);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n找不到该班级!\n");
                else 
				{
                    stuPosition stu = findStu(class->students, stuId);
                    if (!stu) printf("\n找不到该学生!\n");
                    else clearSubList(&stu->subjects);
                }
                break;
            }
            case 14: 
			{ //修改某学生的基本信息
                printf("请输入要修改的学生所在的班级编号、学号、"
                       "修改后的姓名、性别、年龄和电话,中间用空格分隔(none表示不修改该项):\n");
                int classId;
                long stuId;
                char name[10], sex[10], age[10], telephone[20];
                scanf("%d%ld%s%s%s%s", &classId, &stuId, name, sex, age, telephone);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n该班级不存在!\n");
                else 
				{
                    stuPosition stu = findStu(class->students, stuId);
                    if (!stu) printf("\n该学生不存在!\n");
                    else 
					{
                        if (strcmp(name, "none") != 0) strcpy(stu->name, name);
                        if (strcmp(sex, "none") != 0)  stu->sex = !strcmp(sex, "male") ? 1 : 0;
                        if (strcmp(age, "none") != 0)  stu->age = (int) strtol(age, NULL, 0);
                        if (strcmp(telephone, "none") != 0) stu->telephone = strtol(telephone, NULL, 0);
                    }
                }
                break;
            }
            case 15: 
			{ //修改某学生的某门成绩
                printf("请输入要修改的成绩所属学生的班级编号、学号,"
                       "成绩对应的科目名称和修改后的成绩,中间用空格分隔(none表示不修改该项):\n");
                int classId;
                long stuId;
                char subName[10], score[10];
                scanf("%d%ld%s%s", &classId, &stuId, subName, score);
                classPosition class = findClass(classes, classId);
                if (!class) printf("\n该班级不存在!\n");
                else 
				{
                    stuPosition stu = findStu(class->students, stuId);
                    if (!stu) printf("\n该学生不存在!\n");
                    else 
					{
                        subPosition sub = findSub(stu->subjects, subName);
                        if (!sub) printf("\n该成绩不存在!\n");
                        else 
						{
                            if (strcmp(score, "none") != 0)  sub->score = (int) strtol(score, NULL, 0);
                        }
                    }
                }
                break;
            }
            case 16: // 退出学生成绩管理系统
                flag = 0;
                break;
            default:
                printf("操作代号不存在!\n");
                break;
        }
    }
    destroyClassList(&classes); // 释放内存
    return 0;
}


// 科目链表操作集定义
subList createSubList() {
    // 创建科目链表
    subList l;
    if ((l.head = l.tail = (subPosition) malloc(sizeof(struct subNode))) == NULL) 
	{
        printf("内存分配失败!\n");
        exit(1);
    }
    l.head->next = l.head->previous = NULL;
    return l;
}

int subListEmpty(subList l) {
    // 判断科目链表l是否为空
    return l.head->next == NULL;
}

void insertSub(subPosition p, subList *l, char *name, int score) {
    // 在科目链表l中的位置p后插入一个科目节点
    subPosition temp;
    if ((temp = (subPosition) malloc(sizeof(struct subNode))) == NULL) 
	{
        printf("内存分配失败!\n");
        exit(1);
    }
    strcpy(temp->name, name);
    temp->score = score;
    if (p == l->tail) 
	{
        temp->next = p->next;
        temp->previous = p;
        p->next = temp;
        l->tail = temp;
    } 
	else 
	{
        temp->next = p->next;
        temp->previous = p;
        temp->next->previous = temp;
        p->next = temp;
    }
}

void delSub(subPosition p, subList *l) {
    // 删除科目链表l中位于位置p的课程节点
    if (p == l->tail) 
	{
        p->previous->next = p->next;
        l->tail = p->previous;
    } 
	else 
	{
        p->next->previous = p->previous;
        p->previous->next = p->next;
    }
    free(p);
}

subPosition findSub(subList l, char *name) {
    //在科目链表l中查找名为name的课程
    subPosition p;
    for (p = l.head->next; p && strcmp(p->name, name) != 0; p = p->next);
    return p;
}

void clearSubList(subList *l) {
    //清空科目链表l
    subPosition p, temp;
    for (p = l->head->next; p; p = temp) 
	{
        temp = p->next;
        free(p);
    }
    l->tail = l->head;
    l->head->next = NULL;
}

void printSubList(subList l) {
    // 打印科目链表l
    printf("\n");
    subPosition p;
    for (p = l.head->next; p; p = p->next) 
	{
        printf("科目名称:%s", p->name);
        printf(" 成绩:%d\n", p->score);
    }
}

void destroySubList(subList *l) {
    // 摧毁科目链表l
    subPosition p, temp;
    for (p = l->head; p; p = temp) 
	{
        temp = p->next;
        free(p);
    }
    l->head = l->tail = NULL;
}


// 学生链表操作集定义
stuList createStuList() {
    // 创建学生链表
    stuList l;
    if ((l.head = l.tail = (stuPosition) malloc(sizeof(struct stuNode))) == NULL)
	{
        printf("内存分配失败!\n");
        exit(1);
    }
    l.head->subjects = createSubList();
    l.head->next = l.head->previous = NULL;
    return l;
}

int stuListEmpty(stuList l) {
    // 判断学生链表l是否为空
    return l.head->next == NULL;
}

void insertStu(stuPosition p, stuList *l, long id, char *name, int sex, int age, long telephone) {
    // 在学生链表l中的位置p后插入一个学生节点
    stuPosition temp;
    if ((temp = (stuPosition) malloc(sizeof(struct stuNode))) == NULL) 
	{
        printf("内存分配失败!\n");
        exit(1);
    }
    temp->id = id;
    strcpy(temp->name, name);
    temp->sex = sex;
    temp->age = age;
    temp->telephone = telephone;
    temp->subjects = createSubList();
    if (p == l->tail) 
	{
        temp->next = p->next;
        temp->previous = p;
        p->next = temp;
        l->tail = temp;
    } 
	else 
	{
        temp->next = p->next;
        temp->previous = p;
        temp->next->previous = temp;
        p->next = temp;
    }
}

void delStu(stuPosition p, stuList *l) {
    // 删除学生链表l中位于位置p的学生节点
    if (p == l->tail) 
	{
        p->previous->next = p->next;
        l->tail = p->previous;
    } 
	else 
	{
        p->next->previous = p->previous;
        p->previous->next = p->next;
    }
    destroySubList(&p->subjects);
    free(p);
}

stuPosition findStu(stuList l, long id) {
    // 在学生链表l中查找名为name的学生
    stuPosition p;
    for (p = l.head->next; p && p->id != id; p = p->next);
    return p;
}

void clearStuList(stuList *l) {
    // 清空学生链表l
    stuPosition p, temp;
    for (p = l->head->next; p; p = temp) 
	{
        temp = p->next;
        destroySubList(&p->subjects);
        free(p);
    }
    l->tail = l->head;
    l->head->next = NULL;
}

void printStuList(stuList l) {
    // 打印学生链表l
    printf("\n");
    stuPosition p;
    for (p = l.head->next; p; p = p->next) 
	{
        printf("学号:%ld", p->id);
        printf(" 姓名:%s", p->name);
        printf(" 性别:%s", p->sex == 1 ? "male" : "female");
        printf(" 年龄:%d", p->age);
        printf(" 电话:%ld\n", p->telephone);
    }
}

void destroyStuList(stuList *l) {
    // 摧毁学生链表l
    stuPosition p, temp;
    for (p = l->head; p; p = temp) 
	{
        temp = p->next;
        destroySubList(&p->subjects);
        free(p);
    }
    l->head = l->tail = NULL;
}


// 班级链表操作集定义
classList createClassList() {
    // 创建班级链表
    classList l;
    if ((l.head = l.tail = (classPosition) malloc(sizeof(struct classNode))) == NULL) 
	{
        printf("内存分配失败!\n");
        exit(1);
    }
    l.head->students = createStuList();
    l.head->next = l.head->previous = NULL;
    return l;
}

int classListEmpty(classList l) {
    // 判断班级链表l是否为空
    return l.head->next == NULL;
}

void insertClass(classPosition p, classList *l, int classId) {
    // 在班级链表l中的位置p后插入一个班级节点
    classPosition temp;
    if ((temp = (classPosition) malloc(sizeof(struct classNode))) == NULL) 
	{
        printf("内存分配失败!\n");
        exit(1);
    }
    temp->classId = classId;
    temp->students = createStuList();
    if (p == l->tail) 
	{
        temp->next = p->next;
        temp->previous = p;
        p->next = temp;
        l->tail = temp;
    } 
	else 
	{
        temp->next = p->next;
        temp->previous = p;
        temp->next->previous = temp;
        p->next = temp;
    }
}

void delClass(classPosition p, classList *l) {
    // 删除班级链表l中位于位置p的班级节点
    if (p == l->tail) 
	{
        p->previous->next = p->next;
        l->tail = p->previous;
    } 
	else 
	{
        p->next->previous = p->previous;
        p->previous->next = p->next;
    }
    destroyStuList(&p->students);
    free(p);
}

classPosition findClass(classList l, int classId) {
    // 在班级链表l中查找班级编号为classId的班级
    classPosition p;
    for (p = l.head->next; p && p->classId != classId; p = p->next);
    return p;
}

void clearClassList(classList *l) {
    // 清空班级链表l
    classPosition p, temp;
    for (p = l->head->next; p; p = temp) 
	{
        temp = p->next;
        destroyStuList(&p->students);
        free(p);
    }
    l->tail = l->head;
    l->head->next = NULL;
}

void printClassList(classList l) {
    // 打印班级链表l
    printf("\n");
    classPosition p;
    for (p = l.head->next; p; p = p->next) 
		printf("%d班\n", p->classId);
}

void destroyClassList(classList *l) {
    // 摧毁班级链表l
    classPosition p, temp;
    for (p = l->head; p; p = temp) 
	{
        temp = p->next;
        destroyStuList(&p->students);
        free(p);
    }
    l->head = l->tail = NULL;
}


// 用户界面操作定义
void showMainInterface() {
    // 打印学生成绩管理系统主菜单
    printf("\n欢迎使用学生成绩管理系统!\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("10.删除某个学生\n");
    printf("11.删除某个班级内的所有学生\n");
    printf("12.删除某学生的某个成绩\n");
    printf("13.删除某个学生的所有成绩\n");
    printf("14.修改某个学生基本信息\n");
    printf("15.修改某学生的某个成绩\n");
    printf("16.退出学生成绩管理系统\n");
}

五、运行输出结果

六、心得与体会

        通过这次作业,我对于链表有了更深一层的掌握,知道了使用双向链表并完成插入、删除、修改等操作。并且,我明白了在编程过程中始终保持思路清晰的重要性,所以笔和纸必不可少,进行模块划分十分关键。当然,在这过程中我遇到了不少困难,不断试错、不断卡bug,让我摸索出了一些调试的经验,也意识到了耐心细心的可贵。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阮阮的阮阮

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

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

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

打赏作者

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

抵扣说明:

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

余额充值