当前位置:文档之家› 数据结构课程设计(学生成绩管理系统)

数据结构课程设计(学生成绩管理系统)

目录

一、运行环境 0

一、运行环境 (1)

二、设计目的和意义 (1)

2.1设计目的 (1)

2.2设计意义 (1)

三、算法思想 (1)

四、模块划分 (4)

五、数据结构 (5)

六、程序流程图 (6)

七、程序源代码 (8)

八、程序调试过程分析 (18)

九、测试数据 (18)

十、测试结果及分析 (19)

十一、小结 (23)

参考文献 (24)

一、运行环境

硬件环境:电脑

软件环境:vc++6.0

二、设计目的和意义

2.1设计目的

此次课程设计的目的是让学生在学习完C、数据结构等课程基础上,进一步掌握设计、实现较大系统的完整过程,包括系统分析、编码设计、系统集成、以及调试分析,熟练掌握数据结构的选择、设计、实现以及操作方法,为进一步的应用开发打好基础。

2.2设计意义

此次设计意义在于让我们更好的去掌握C的基本语法、函数以及Visual C++集成编译环境。掌握树、图、链表等基本数据结构及其应用。掌握程序流程以及基本应用方法。应用软件工程方面的知识,熟悉软件开发的流程。

通过本课程设计,培养学生进行软件设计能力。首先进行需求分析,针对目标对象完成程序结构设计、对象设计、主要数据结构设计、输入输出设计、人机界面设计等。

三、算法思想

整个系统除了主函数外,另外还有12个函数,实现十大功能:菜单选择、输入功能、显示功能、查找功能、删除功能、排序功能、插入功能、保存功能、读取功能、修改。各个函数的详细设计说明分别如下:

1、主函数 main()

利用无限次循环for(;;)和swithch()实现各函数的调用,系统根据输入的数字选项来调用相应的函数。

2、初始化函数 STUDENT *init()

这是一个无参函数,里面只有一个语句,它的作用是使链表初始化,使head的值为NULL。比如:没有这个函数的话,在你没有输入任何数据的情况下,去执行显示功能的时候会显示一些乱码!

3、菜单选择函数 int menu_select();

这是一个无参函数,主要实现“功能选择”的界面,在这个界面里有显示系统的九大功能,根据每个功能前面的序号进行选择,中间还显示系统当前的时间。等执行完每一个函数功能后,按任一键回到主界面也要通过这个函数来实现!

4、输入记录函数 STUDENT *create()

这是一个无参函数,用来执行第学生成绩记录的输入,当学生为0时停止输入,函数结束后,带回一个指向链表头的指针head。

算法:先声明一个首节点head,并将head->next设为NULL。每输入一个数据就声明一个新节点p,把p->next设为NULL,并且链接到之前列表的尾端。

5、显示记录函数 void print(STUDENT *head)

这是一个不返回值的有参函数,形参为“链表头的指针”,负责对全部学生成绩记录的输出,不足之处就是不能对学生成绩进行分页显示。

算法:先将p结点的指针指向第一个结点,将p结点(即第一个结点)的数据输出。然后再将p结点的指针指向p指针的的指针(即下一结点),将p结点(即第一结点)的数据输出。重复执行此步聚直到p指针指向NULL为止。

6、查找记录函数 void search(STUDENT *head)

这是一个不返回值的有参函数,形参为“链表头的指针”,实现按姓名对某个学生进行查找,并显示所查找到的记录。

算法:采用线性查找法往下一个节点查找。输入所要查找的学生的姓名s,设一个指针变量p,先指向第一个结点,当strcmp(p->name,s) && p != NULL时,使p后移一个结点,如果p!=NULL,输出p所指的结点。

7、删除记录函数 STUDENT *delete(STUDENT *head)

这是一个有参函数,形参为“链表头的指针”,先输入要删除的学生记录的学号,找到后显示该学生信息,等确认后便可按“Y”进行删除。

算法:从p指向的第一个结点开始,检查该结点中的num值是否等于输入的要求删除的那个学号。如果相等就将该结点删除,如不相等,就将p后移一个结点,再如此进行下去,直到遇到表尾为止。

8、排序函数 STUDENT *sort(STUDENT *head)

这是一个有参函数,形参为“链表头的指针”,按学生成绩的平均分高低进行排序,还可以显示名次。

9、修改函数 STUDENT *xiugai(STUDENT *head)

这是一个有参数函数,形参为“链表头的指针”,首先按学生姓名对要修改的学生记录进行查找,然后对找到的记录进行修改。

算法:采用线性查找法往下一个节点查找。输入所要查找的学生的姓名s,设一个指针变量p,先指向第一个结点,当strcmp(p->name,s) && p != NULL时,使p后移一个结点,如果p!=NULL,修改p所指的结点的相关记录,修改完成后对记录进行输出,然后重新调用排序sort函数,对新修改的数据进行排序。

10、插入函数 STUDENT *insert(STUDENT *head,STUDENT *new)

这是一个有参函数,形参有两个,一个是“链表头的指针”,一个是“待插入指针”,按照原来成绩平均分的高低进行插入,插入后会重新进行排序,并返回。

算法:先将学生的成绩按平均分由高分到低分进行排序,再插入一个新生的结点,要求按平均分的高低顺序插入。先用指针变量p0指向待插入的结点,p1指向第一个结点。如果p0->averageaverage,则待插入的结点不应插在p1所指的结点之前。此时将p1后移,并使p2指向刚才p1所指的结点。重复以上的步骤,直到p0->average>=p1->average为止。这时将p0指向的结点插到p1所指结点之前。但是如果p1所指的已是表尾结点,则p1就不应后移了。如果p0->average比所有结点的average都小,则应将p0所指的结点插到链表末尾。如果插入的位置既不在第一个结点之前,又不在表尾结点之后,则将p0的值赋给p2->,使p2->next指向待插入的结

点,然后将p1的值赋给p0->next,使得p0->next指向p1指向的变量。如果插入位置为第一个结点之前,则将p0赋给head,将p1赋给p0->next。如果要插到表尾之后,应将p0赋给p1->next,NULL赋给p0->next。最后再调用排序的函数,将学生成绩重新排序.

11、保存数据到文件函数 void save(STUDENT *head)

这是一个不返回值的有参函数,形参为“链表头的指针”,可以把学生记录保存在电脑上由自己任意命名的二进制文件。

12、从文件读数据函数 STUDENT *load()

这是一个不返回值的有参函数,形参为“链表头的指针”,根据输入的文件地址进行读取。

四、模块划分

学生成绩管理的设计,除了主函数和初始化函数外,主要还设计了十个功能函数:菜单选择、输入功能、输出功能、查找功能、删除功能、排序功能、插入功能、保存功能、读取功能、修改函数。通过分组设计现实现部分功能函数说明如下:

1、菜单选择:int menu_select();

提供十种可以选择的操作,在main函数中通过switch语句调用菜单menu_select()函数,进入不同的功能函数中完成相关操作。

2、输入功能:STUDENT *create();

通过一个for循环语句的控制,可以一次完成无数条记录的输入。并将其存入链表。

3、输出功能:void print(STUDENT *head);

通过一个while的循环控制语句,在指针p!=0时,完成全部学生记录的显示。知道不满足循环语句,程序再次回到菜单选择功能界面。

4、查找功能:void search(STUDENT *head);

通过strcmp来判断是否找到所需查找的学生记录,在不满足该条件时,通过while

语句完成结点的下移,最后若查找成功则完成显示。返回主菜单界面。

5、删除功能: STUDENT *Delete(STUDENT *head);

按想要删除的学生的学号首先进行查找,通过指针所指向结点的下移来完成,如果找到该记录,则完成前后结点的连接,同时对以查找到的结点进行空间的释放,最后完成对某个学生记录进行删除,并重新存储。

6、修改功能:STUDENT *xiugai(STUDENT *head);

首先通过想核对想要修改的学生姓名进行查到,相当于调用一次查找函数search,如果查找成功则对数据进行修改,最后计算其总分和平均分,调用一次排序函数sort,重新进行排序,并重新存储记录。

五、数据结构

定义了一个typedef struct stu 的结构体数组,相关描述如下:

#define LEN sizeof(STUDENT)

typedef struct stu /*定义结构体数组用于缓存数据*/

{

char num[6];

char name[20];

int score[3];

int sum;

float average;

int order;

struct stu *next;

}STUDENT;

六、程序流程图

6.1、程序的总体模块流程图如下:

图6-1

6.2、删除学生记录流程图如下:

图6-2

6.3、插入学生记录流程图如下:

图6-3

七、程序源代码

#include

#include

#include /*其它说明*/

#include /*字符串函数*/

#include /*字符操作函数*/

#define LEN sizeof(STUDENT)

typedef struct stu /*定义结构体数组用于缓存数据*/

{

char num[6];

char name[20];

int score[3];

int sum;

float average;

int order;

struct stu *next;

}STUDENT;

/*函数原型*/

STUDENT *init(); /*初始化函数*/

int menu_select(); /*菜单函数*/

STUDENT *create(); /*创建链表*/

void print(STUDENT *head); /* 显示全部记录*/

void search(STUDENT *head); /*查找记录*/

STUDENT *Delete(STUDENT *head); /*删除记录*/

STUDENT *sort(STUDENT *head); /*排序*/

STUDENT *insert(STUDENT *head,STUDENT *New); /*插入记录*/

STUDENT *xiugai(STUDENT *head); /*修改记录*/

void save(STUDENT *head); /*保存文件*/

STUDENT *load(); /*读文件*/

/*主函数界面*/

void main()

{STUDENT *head,New;

head=init(); /*链表初始化,使head的值为NULL*/

for(;;) /*循环无限次*/

{switch(menu_select())

{

case 1:head=create();break;

case 2:print(head);break;

case 3:search(head);break;

case 4:head=Delete(head);break;

case 5:head=sort(head);break;

case 6:head=insert(head,&New);break; /*&new表示返回地址*/ case 7:save(head);break;

case 8:head=load(); break;

case 9:xiugai(head);break;

case 10:exit(0); /*如菜单返回值为9则程序结束*/ }

}

}

/*初始化函数*/

STUDENT *init()

{

return NULL; /*返回空指针*/

}

/*菜单选择函数*/

menu_select()

{int n;

printf("****************************************************\n");

printf("\t\t Welcome to\n");

printf("\n\t\t The student score manage system\n");

printf("********************MENU**************************\n");

printf("\t\t\t1. 输入学生记录\n"); /*输入学生成绩记录*/ printf("\t\t\t2. 输出学生记录\n"); /*显示*/

printf("\t\t\t3. 查找学生记录\n"); /*寻找*/

printf("\t\t\t4. 删除学生记录\n"); /*删除*/

printf("\t\t\t5. 将学生成绩进行排序\n"); /*排序*/

printf("\t\t\t6. 插入一个新的学生记录\n"); /*插入*/

printf("\t\t\t7. 保存记录\n"); /*保存*/

printf("\t\t\t8. 读取记录\n"); /*读取*/

printf("\t\t\t9. 修改记录\n"); /*修改*/

printf("\t\t\t10. 退出\n"); /*退出*/

printf("\n\t\t 夏翠玉、陈洁丽.\n");

printf("******************************************************\n");

do{

printf("\n\t\t\t输入您的选择(1~10):");

scanf("%d",&n);

}while(n<1||n>10); /*如果选择项不在1~9之间则重输*/

return(n); /*返回选择项,主函数根据该数调用相应的函数*/ }

/*输入函数*/

STUDENT *create()

{int i,s,k;

int j=0;

STUDENT *head=NULL,*p; /* 定义函数.此函数带回一个指向链表头的指针*/ system("cls");

printf("\n请输入您想输入的学生个数:");

scanf("%d",&k);

for(j=0;j

{p=(STUDENT *)malloc(LEN); /*开辟一个新的单元*/

if(!p) /*如果指针p为空*/

{printf("\n输出内存溢出."); /*输出内存溢出*/

return (head); /*返回头指针,下同*/

}

printf("输入学号(0:list end):");

scanf("%s",p->num);

if(p->num[0]=='0') break; /*如果学号首字符为0则结束输入*/ printf("输入姓名:");

scanf("%s",p->name);

printf("请分别输入语文、数学、英语的分数 %d scores\n",3);/*开始输入*/ s=0; /*计算每个学生的总分,初值为0*/

for(i=0;i<3;i++) /*3门课程循环3次*/

{

do{

printf("score%d:",i+1);

scanf("%d",&p->score[i]);

if(p->score[i]<0 || p->score[i]>100) /*确保成绩在0~100之间*/

printf("Data error,please enter again.\n");

}while(p->score[i]<0 || p->score[i]>100);

s=s+p->score[i]; /*累加各门成绩*/

}

p->sum=s; /*将总分保存*/

p->average=(float)s/3;/*先用强制类型转换将s转换成float型,再求平均值*/ p->order=0; /*未排序前此值为0*/

p->next=head; /*将头结点做为新输入结点的后继结点*/

head=p; /*新输入结点为新的头结点*/

}

return(head);

}

/* 显示全部记录函数*/

void print(STUDENT *head)

{

STUDENT *p; /*移动指针*/

system("cls");

p=head; /*初值为头指针*/

printf("\n******************************STUDENT***************\n");

printf("----------------------------------------------------\n");

printf("| 学号 | 姓名 | 语文 | 数学 | 英语 | 总分 | 平均成绩 | 名次 |\n");

printf("------------------------------------------------------\n");

while(p!=NULL)

{

printf("| %4s | %-4s | %3d | %3d | %3d | %3d | %4.2f | %-5d|\n",

p->num,p->name,p->score[0],p->score[1],p->score[2],p->sum,p->average,p

->order);

p=p->next;

}

printf("----------------------------------------------------\n");

printf("**************************END*************************\n");

}

/*查找记录函数*/

void search(STUDENT *head)

{STUDENT *p; /* 移动指针*/

char s[5]; /*存放姓名用的字符数组*/

system("cls");

printf("请输入查找者姓名.\n");

scanf("%s",s);

p=head; /*将头指针赋给p*/

while(strcmp(p->name,s) && p != NULL) /*当记录的姓名不是要找的,或

指针不为空时*/

p=p->next; /*移动指针,指向下一结点*/

if(p!=NULL) /*如果指针不为空*/

{printf("\n**************************FOUND*******************\n");

printf("------------------------------------------------------\n");

printf("| 学号 | 姓名 | 语文 | 数学 | 英语 | 总分 | 平均成

绩 | 名次 |\n");

printf("-------------------------------------------------------\n");

printf("| %4s | %4s | %3d | %3d | %3d | %3d | %4.2f | %-5d|\n",

p->num,p->name,p->score[0],p->score[1],p->score[2],p->sum,p->average,p->or der);

printf("-------------------------------------------------------\n");

printf("**************************END************************\n");

}

else

printf("\n无此记录.\n",s); /*显示没有该学生*/

}

/*删除记录函数*/

STUDENT *Delete(STUDENT *head)

{

STUDENT *p1,*p2; /*p1为查找到要删除的结点指针,p2为其前驱指针*/ char c,s[6]; /*s[6]用来存放学号,c用来输入字母*/

system("cls");

printf("请输入要删除的学生的学号: ");

scanf("%s",s);

p1=p2=head; /*给p1和p2赋初值头指针*/

while(strcmp(p1->num,s) && p1 != NULL) /*当记录的学号不是要找的,或指针不为空时*/

{p2=p1; /*将p1指针值赋给p2作为p1的前驱指针*/ p1=p1->next; /*将p1指针指向下一条记录*/

}

if(strcmp(p1->num,s)==0) /*学号找到了*/

{printf("***********************FOUND************************\n");

pri-----------------------------------------------------------\n");

printf("| 学号 | 姓名 | 语文 | 数学 | 英语 | 总分 | 平均成绩 | 名次 |\n");

printf("-------------------------------------------------\n");

printf("| %4s | %4s | %3d | %3d | %3d | %3d

| %4.2f | %-5d|\n",

p1->num,p1->name,p1->score[0],p1->score[1],p1->score[2],p1->sum,p1->averag e,p1->order);

printf("-----------------------------------------------------\n");

printf("***************************************END***************** *********************\n");

printf("您确定要删除该学生的记录吗 Y/N ?"); /*提示是否要删除,输入Y 删除,N则退出*/

for(;;)

{scanf("%c",&c);

if(c=='n'||c=='N') break; /*如果不删除,则跳出本循环*/

if(c=='y'||c=='Y')

{

if(p1==head) /*若p1==head,说明被删结点是首结点*/

head=p1->next; /*把第二个结点地址赋予head*/

else

p2->next=p1->next;

free(p1);/*否则将一下结点地址赋给前一结点地址*/

printf("\n学号为 %s 的学生记录已被删除.\n",s);

printf("别忘了重新存储记录.\n");break; /*删除后就跳出循环*/

}

}

}

else

printf("\n找不到学号为 %s 的学生记录.\n",s); /*找不到该结点*/

return(head);

}

/*修改函数*/

STUDENT *xiugai(STUDENT *head)

{

STUDENT *q; /* 移动指针*/

char s[5]; /*存放姓名用的字符数组*/

system("cls");

printf("请输入查找者姓名.\n");

scanf("%s",s);

q=head; /*将头指针赋给p*/

while(strcmp(q->name,s) && q != NULL) /*当记录的姓名不是要找的,或指针不为空时*/

q=q->next; /*移动指针,指向下一结点*/

if(q!=NULL) /*如果指针不为空*/

{printf("\n************************FOUND*************************\n");

int sum1,i;

printf("\n请在下面输入要修改成的学生的记录.\n"); /*提示输入记录信息*/

printf("学号:");

scanf("%s",q->num);

printf("姓名:");

scanf("%s",q->name);

printf("分别输入 %d 科的分数.\n",3);

sum1=0; /*保存新记录的总分,初值为0*/

for(i=0;i<3;i++)

{

do{

printf("score%d:",i+1);

scanf("%d",&q->score[i]);

if(q->score[i]>100||q->score[i]<0)

printf("Data error,please enter again.\n");

}while(q->score[i]>100||q->score[i]<0);

sum1=sum1+q->score[i]; /*累加各门成绩*/

}

q->sum=sum1;

q->average=(float)sum1/3;

q->order=0;

printf("--------------------------------------------------------\n");

printf("| 学号 | 姓名 | 语文 | 数学 | 英语 | 总分 | 平均成

绩 | 名次 |\n");

printf("--------------------------------------------------------\n");

printf("| %4s | %4s | %3d | %3d | %3d | %3d | %4.2f | %-5d|\n",

q->num,q->name,q->score[0],q->score[1],q->score[2],q->sum,q->average,q->or der);

printf("--------------------------------------------------------\n");

printf("*************************END***************************\n");

head=sort(head); /*调用排序的函数,将学生成绩重新排序*/

printf("\n学生 %s 已经修改成功.\n",q->name);

printf("请别忘了重新存储.\n");

}

else

printf("\n无此记录.\n",s); /*显示没有该学生*/

return(head);

}

八、程序调试过程分析

(1)刚开始没有那个初始化函数,程序运行后,没有输入任何数据就试得去执行显示功能,结果显示的是一些乱码!加入初始化函数后,这种现象也随之消失。

(2)刚开始执行输入函数,按学号顺序输入十个学生的成绩,输完后执行显示功能,学生成绩记录是按学号的反顺序显示的,试着在其中增加一些语句,希望能把学号按正常顺序显示,但暂时没有成功,所以在输入成绩时只能按学号反顺序输入,最后就按学号正常顺序输出了。

(3)刚开始时,先把成绩按平均分排序,再插入一个学生的成绩,执行显示功能,虽然插入的学生的成绩能正常插入,但该学生的名次为0。后来,在插入成绩之后,调用排序函数,把所有成绩重新排序一次。

(4)在输入函数中设了一个无限循环,可以输入无数个学生的成绩信息,当学号为0的时候则停止输入。

(5)输入太多个学生的成绩时,屏幕显示不能控制为一页一页显示,所以为了方便起见,不要输入太多记录,十七左右为最佳。

(6)在没有输入任何信息的情况下,去执行排序功能,最后显示有一个记录,学号、姓名为空白,成绩都为0,名次为1。

(7)在输入选项时不能输入字母,否则会死循环,建议不要乱输字母。

(8)在编写修改函数时,发现平均成绩和总成绩没有变化,原因为循环语句之后没有进行数据的重新赋值,以至于新的数据没能插进链表。

九、测试数据

下面对所设计系统进行数据测试:

1、在主菜单选择1、输入学生记录,分别输入三组学生记录为:

2、在主菜单选择6、插入一个新的学生记录,插入数据为:

学号4 姓名Gu 语文成绩45 数学成绩 44 英语成绩 33

3、在主菜单选择9、修改记录,修改的数据为:

学号 5 姓名 ze 语文成绩45 数学成绩33 英语成绩55

4、在主菜单选择2、输出学生记录,得到一组如下的输出:

6、在主菜单选择5、将学生成绩进行排序,然后在选择2、进行一次输出,得到最后记录:

7、在主菜单分别选择7、保存记录和8、读取记录,进行一次文件的读写测试。

十、测试结果及分析

10.1、测试结果如下:

相关主题
文本预览
相关文档 最新文档