数据结构实验报告
一. 具体设计 Ⅰ顺序表
㈠存储结构定义
采用了两个结构体,其中Student结构体用于存储学生的各项信息,包括学号int num;姓名char name[20];英语成绩float english;数学成绩float math;数据结构成绩float database;总分float sum;平均分float average; 顺序表的结构体sqlist中包含的数据项是Student结构体,还有存储当前长度的int length;及当前分配的存储容量的int listsize;
㈡函数功能定义及具体功能介绍
⑴录入信息int Input(sqlist *L)
每次输入学生的所有信息,输入完后提示是否继续输入 ⑵显示所有学生信息int Display(sqlist *L) ⑶插入一条记录到表尾void Insert(sqlist *L)
⑷删除一条记录int Delete(sqlist *L)包括1.按姓名删除2.按学号删除
⑸统计成绩int Statistic(sqlist *L)包括全班平均成绩,各科平均成绩,总分最高分,总分最低分,各科最高分,各科最低分以及各科及格率
⑹查找int Search(sqlist *L)查找方法包括1.顺序查找2.二分查找按查找内容又包括1.按学号查找2.按姓名查找,若查找成功则显示查找到的学生信息,若查找失败则提示“查找失败!” ⑺排序int Sort(sqlist *L)排序方法包括1.直接插入排序2.折半插入排序3.冒泡排序4.直接选择排序,排序内容包括1.按学号排序2.按英语成绩排序3.按高数成绩排序4.按数据结构成绩排序5.按总分排序
(0) 退出程序void tuichu(sqlist *L)释放占用的内存空间,显示\"谢谢使用!\",然后关闭所有文
件,终止正在进行的程序
(9) 主菜单int menu(),每次进行完一次功能实现后再次弹出,方便用户使用 (10) 主函数int main(),用switch语句根据用户的选择进行相应的操作
㈢具体设计思路及过程
⑴录入信息int Input(sqlist *L),初始length为0,每录入一个学生length加一,然后显示提示信息是否继续,若继续则要再录入,所以要把这个整体的外面再套一层while循环,但是在写的过程中也遇到了一个困难,还没有输入继续y,就让输入学生信息,通过百度,知道了C有一个输入的缓冲区,所以在每次输入前都请空了缓冲区,防止读入缓冲区余下的内容。运行截图如下:
⑵显示所有学生信息int Display(sqlist *L) 把存储在顺序表中的内容全部读出即可,但是当用户还没有输入数据的时候就选择了显示所有学生信息,就显示一个提示信息\"请先输入数据!\",然后回到主界面 运行截图如下:
⑶插入一条记录到表尾void Insert(sqlist *L)即输入学生信息保存到数组下标为L->length,然后让L->length加一即可 运行截图如下:
⑷删除一条记录int Delete(sqlist *L)包括1.按姓名删除2.按学号删除,所以要用一个int型变量存储学生的选项。当用户还没有输入数据的时候如果选择了删除一条记录,就显示一个提示信息\"请先输入数据!\",然后回到主界面。若顺序表中存在数据就先用顺序查找法查找是否存在这个学生,如果存在那么把后面的学生信息前移一位,然后L->length--,如果没有找到这个学生的信息就显示\"要删除记录不存在!\",然后返回主界面。运行截图如下:
⑸统计成绩int Statistic(sqlist *L),因为要统计的信息包含总分和3门课程,所以要设置多个计数器,而且计算及格率的计数器应设为float,否则两个整数相除是整数,结果会有误。实现时从第一个学生信息开始依次加到最后一个即可,运行截图如下:
⑹查找int Search(sqlist *L) 当用户还没有输入数据的时候如果选择了查找,就显示一个提示信息\"请先输入数据!\",然后回到主界面。如果顺序表中存在数据就开始查找,找方法包括1.顺序查找2.二分查找按查找内容又包括1.按学号查找2.按姓名查找,所以要设置两个int 型的变量ch1,ch2来读入选择的内容,然后再通过switch语句进入选择的查找方法或查找的内容。按学号查找的比较语句要用”==”,按姓名查找的比较语句就要用strcmp()函数,顺序查找法当计数器大于等于L->length时,输出\"查找失败!\",然后回到主界面,二分查找法当low>high时就输出\"查找失败!\",然后回到主界面。 运行截图如下:
⑺排序int Sort(sqlist *L)排序方法包括1.直接插入排序2.折半插入排序3.冒泡排序4.直接选择排序,排序内容包括1.按学号排序2.按英语成绩排序3.按高数成绩排序4.按数据结构成绩排序5.按总分排序,所以要设置两个int 型的变量ch1,ch2来读入选择的内容,然后再通过switch语句进入选择的排序方法然后进入要排序的内容再进行相应的排序。自己一开始写的时候复制记录是把结构体中的所有内容按照相应的复制方法依次复制过去,后来意识到结构体是可以直接复制的,所以又进行了改进,而且把数组中的第一个空闲,当作监视哨。
(0) 退出程序void tuichu(sqlist *L),最初自己只是显示出谢谢使用!,然后用exit(0)终止程序,
后来意识到还应释放存储学生信息的结构体,所以又增加了if(!L->stu)free(L->stu);
(9)主菜单int menu(),显示标题,和大致功能,用户根据功能前的编号选择进入相应的函数,执行相应的功能,所以用一个int型的变量来录入用户的选择,并且这个函数的返回值类型为int ,以供main函数使用,为了防止用户的输入错误,加了一个while语句,当输入错误时,提示\"输入错误!请重新输入:\",直到用户输入正确为止。
(10)main函数,先定义顺序表,然后初始化,并且为了查找、排序方便将第一个当哨兵,所以LL->length初值为1,用一个 while(1)和switch(menu())执行用户的选择操作,直到选择了退出。
Ⅱ单链表
㈠存储结构定义
采用了一个结构体表示单链表里面包含保存学生学号的int stuid,姓名的char name[20],英语成绩的float english,数学成绩的float math,数据结构成绩的float database,总分的float sum,平均分的float average;指示结点地址的指针struct LNode *next 。
㈡函数功能定义及具体功能介绍
⑴录入信息LinkList Input() 每次输入学生的所有信息,先输入要输入的学生人数然后逆序建表、完后提示是否继续输入 ⑵显示所有学生信息void Display(LinkList L) ⑶插入一条记录到表尾void Insert(LinkList L)
⑷删除一条记录void Delete(LinkList L)包括1.按姓名删除2.按学号删除
⑸顺序查找某个学生void Search(LinkList L)按查找内容包括1.按学号查找2.按姓名查找,若查找成功则显示查找到的学生信息,若查找失败则提示“没有该学生的信息” ⑹显示各科最高分void Max(LinkList L)) ⑺各科平均分void Average(LinkList L)
(8)排序void Sort(LinkList L)排序方法包括1.直接插入排序2.冒泡排序3.直接选择排序,排序内容包括1.按学号排序2.按英语成绩排序3.按高数成绩排序4.按数据结构成绩排序5.按总分排序
(1) 退出程序void tuichu()显示\"谢谢使用!\",然后关闭所有文件,终止正在进行的程序 (9) 主菜单void Menu(),每次进行完一次功能实现后再次弹出,方便用户使用 (10) 主函数int main(),用switch语句根据用户的选择进行相应的操作
㈢具体设计思路及过程
⑴录入信息LinkList Input(),先建立一带头结点的空单链表,然后逆序建立存储学生信息的单链表,录入时,因为当时设计时想了两种录入方法,一种是顺序表中的每次输入一个学生信息然后输出提示让用户判断是否还要输入,另一种是先确定了输入人数再建立,所以在单链表中采用了第二中。先输入要输入的人数,所以要把这个整体的外面再套一层for循环,依次用malloc生成新结点,再把把新结点插入到链表头部。 运行截图如下:
⑵显示所有学生信息int Display(sqlist *L) 把存储在顺序表中的内容全部读出即可,但是当用户还没有输入数据的时候就选择了显示所有学生信息,就显示一个提示信息\"请先输入数据!\",然后回到主界面,所以先判断链表是否为空,在外层要嵌套一层if......else语句,然后内层用一个for循环把存储在顺序表中的内容全部读出。 运行截图如下:
⑶插入插入单个学生到表头void Insert(LinkList L),因为是采用逆序建表,所以是插入到表头。先用malloc申请一个新的结点空间,然后录入各项信息插入到表头修改指针即可。 运行截图如下:
⑷删除一条记录void Delete(LinkList L)包括1.按姓名删除2.按学号删除。所以要设置两个int型变量,一个存储存储用户的选项,然后用if...else语句进入相应的功能区;另一个存储要删除的,用户输入的学号信息;还要设一个char型数组,存储用户输入的要删除的姓名信息。当用户还没有输入数据的时候如果选择了删除一条记录,就显示一个提示信息\"请先输入数据!\",然后回到主界面。若单链表中存在数据就先用顺序查找法查找是否存在这个学生,如果存在因为单链表删除结点要知道要删除的这个结点的前一个结点的位置,所以要用一个指针记录,一共有3个指针,L是头结点的头指针,,最后p指向要删除的结点的前一个位置,q指向p的下一个结点,即最后指向要删除的结点。找到后修改p,q这个两个指针的指向即可,最后输出要删除的学生信息后释放要删除的结点。如果没有找到这个学生的信息就显示\"要删除记录不存在!\",然后返回主界面。 运行截图如下:
⑸顺序查找某个学生void Search(LinkList L)单链表只能采用顺序查找法,不能采用折半查找。按查找内容包括1.按学号查找2.按姓名查找,若查找成功则显示查找到的学生信息,若查找失败则提示“没有该学生的信息”。所以要设置两个int型变量,一个存储存储用户的选项,然后用if...else语句进入相应的功能区;另一个存储要删除的,用户输入的学号信息;还要设一个char型数组,存储用户输入的要删除的姓名信息。 运行截图如下:
⑹显示各科最高分void Max(LinkList L))⑺各科平均分void Average(LinkList L)是两个统计成绩的功能,因为要统计3科成绩,所以要设多个float型变量,采用顺序遍历,依次统计。 运行截图如下:
(8)排序void Sort(LinkList L)排序方法包括1.直接插入排序2.冒泡排序3.直接选择排序,排序内容包括1.按学号排序2.按英语成绩排序3.按高数成绩排序4.按数据结构成绩排序5.按总分排序,所以要设置两个int 型的变量ch1,ch2来读入选择的内容,然后再通过switch语句进入选择的排序方法然后进入要排序的内容再进行相应的排序。1.直接插入排序中L是带头结点的单链表,基本方法是第一元素有序,从第二元素起依次插入。2.冒泡排序,采用交换结点中的元素,不改变指针。3.直接选择排序一趟找出一个关键字最小的结点,其数据和当前结点进行交换;若要交换指针,需记下当前结点和最小结点的前驱指针。运行截图如下:
二.改进
1.为了输出的界面显示的学生信息整齐,最初是根据运行的结果计算了一下应大致空多少空格,后来在Java课上用到了制表符,自己又通过上网百度进一步了解了制表符的功能就将
其全部改为了制表符对齐。
2.为了尽量减少用户的输入错误而导致的程序意外终止,⑴在录入用户的选择时加入了while语句,当输入错误时,提示\"输入错误!请重新输入:\",直到用户输入正确为止。⑵而且在需要顺序表中有数据才能进行的操作里都加上了判断顺序表是否为空,若顺序表为空就提示用户应先输入数据,再返回主界面。 3.在结构体中学号定义的是int型,存储的位数有限,而且实际上我们的学号都是12多位的,所以最好用一个char型的数组来存放学号的信息,还应在结构体中加上班级,年级等信息,这样面对的整体才是全校的学生,而且还可以加上文件的读写,使这个学生成绩管理系统的应用更广泛。
三.总结反思
1.虽然大一的时候也做过学生成绩管理系统,但现在看来当时写的程序健壮性和规范性太差。这个学期写学生成绩管理系统时脑子里已经有了清晰的想法,知道了选择好存储结构后再进行编写相应的操作的函数,里面写的每一个函数都是基于老师上课所讲的,通过老师的讲授,自己再实际的编写运用,对算法的思想又加深了认识,进步不少。初步写好后自己又根据在现实中的使用情况做了几处改进,除了老师要求的功能外又增加了一些常用的功能,如查找的按学号查找,按姓名查找,排序的按学号,各科成绩和总成绩排序还有统计各科的平均分,最高分,及格率等,由于时间有限还有一些改进会在假期中完成。 2.在写程序的过程中经常由于少了个括号而出现错误,后来发现课本上老师的程序都是在括号的后面加上一句注释指明括号的范围是哪里,自己就也这样写了,基本上由于括号而出现的错误就没有了。