汇编语言综合实验学生成绩排序单链表实现.docx
《汇编语言综合实验学生成绩排序单链表实现.docx》由会员分享,可在线阅读,更多相关《汇编语言综合实验学生成绩排序单链表实现.docx(22页珍藏版)》请在冰点文库上搜索。
汇编语言综合实验学生成绩排序单链表实现
《汇编语言》课程综合性实验报告
实验题目
显示学生名次表
一、实验目的
通过显示学生成绩名次表,进行汇编语言程序设计应用的综合性训练。
综合运用汇编语言循环程序、子程序、宏指令编程方法,提高汇编语言程序设计能力的应用水平。
二、设备与环境
PC兼容机、Windows操作系统、汇编程序masmforwindows2012。
三、实验内容
1.实验内容:
编制一程序,要求接收从键盘输入的一个班的学生的学号、姓名、成绩,对学生的成绩进行排序,再按学号顺序和学生名次顺序分别把学生成绩显示出来。
2.实验要求:
①必须画程序流程图。
②本程序要求要有多重循环和子程序及宏,其中成绩输入、计算学生名次、显示学生名次都分别用子程序,也可用宏处理。
③要求用菜单选择,输入1时按学号顺序输出成绩(包括姓名、学号、成绩、名次),输入2时按成绩排名顺序输出成绩(包括姓名、学号、成绩、名次)。
四、实验结果及分析
1.主界面的设计与实现:
(1)程序分为两个菜单:
①一级菜单:
完成学生成绩的录入或从本地文件中载入学生成绩信息。
(图1-1)用户输入对应选项1、2、3或L、C、E,分别执行相应的功能。
输入1(或L):
表示从文件中读取学生成绩信息;
输入2(或C):
表示重新录入学生成绩信息,并保存到文件中;
输入3(或E):
表示退出程序。
②二级菜单:
完成对学生成绩信息的排序,并输出排序后结果。
(图1-2)
输入1:
完成按学号排序(升序)并输出排序后结果;
输入2:
完成按总分排序(降序)并输出排序后结果;
输入3:
返回一级菜单。
图1-1程序主界面:
图1-2程序二级菜单界面:
2.排序功能的实现:
图1-2输入学生成绩界面:
图1-4按总分排序输出学生成绩信息:
3.设计思路:
(1)数据定义:
一个数据元素(一个学生的数据项)应该为一个结构类型,定义如下:
STUDENTSTRUC;定义学生结构体
LINKDW0;单链表指针,指向下一个节点偏移地址
IDDB'000';学号
NAMESDB'$$$$$$$$';姓名
CSCOREDB?
;语文成绩
MSCOREDB?
;数学成绩
SUMDB?
;总分
STUDENTENDS
其中,LINK字段为链指针,指向数据元素的后续地址,它占用一个字,其初值为0;ID字段为3个字节,存放学号,为了输入输出方便,学号以3位十进制数字的字符存放;NAMES字段为8个字节,存放姓名,为了方便输出,预设8个‘$’符号;CSCORE字段、MSCORE字段和SUM字段分别为学生的语文成绩、数学成绩、总成绩,由于这3个字段的值不超过200,分别以一个字节的二进制存放即可。
每一个学生的数据信息为结构S这样一个数据元素。
则10个学生需要分配10个这样的数据元素的存储单元。
用上面的结构名STUDENT作为伪指令定义学生数组如下:
S_ARRAYSTUDENT10DUP(<>);预设学生人数为10
S_ARRAY是一个结构类型的数组,它包括10个元素,每一个元素为一个STUDENT类型的结构。
在建立链表的过程中,会用数组元素的首地址装填LINK字段,为了避免冲突,数组元素的首地址不能为0和1,因此,在数据段定义中定义S_ARRAY数组之前,用DW分配了一个字,使数组S_ARRAY的第一个元素的位移量不为0,也不为1。
(2)方法和步骤:
这个程序主要包括3个部分:
输入数据、按学生的总成绩由高到低(降序)建立链表和按学生名次输出学生信息。
①输入数据。
从数组的第一个元素开始,顺序填装数据元素,因此设置循环将S_ARRAY数组第一个元素的位移量送至BX,每一次循环,BX加上TYPES_ARRAY(值为16),使BX指向S_ARRAY数组中下一个元素的起始地址。
装填每个元素的各字段值:
输入学号存放到S_ARRAY数组元素的ID字段;输入姓名、语文成绩、数学成绩并分别存放到数组元素的NAMES字段、CSCORE字段和MSCORE字段;将CSCORE字段和MSCORE字段的值相加得到总成绩送入SUM字段。
②按学生的总成绩由高到低进行排序建立链表。
这一部分任务是按学生总成绩由高到低进行排序。
采用单链表方式,给数据元素的链指针LINK字段装填数据,使LINK字段指向它的后继数据元素。
步骤如下:
Ⅰ.初始时,数组元素的每个LINK字段值为0,表示数组元素没有被选中。
扫描数组元素的SUM字段,从中找到第一个最大的数,将这个数组元素设置为链表的头,保存这个数组元素的位移量,并将其LINK字段设置为1,标记这个数组元素已被选中但尚未装填链指针。
Ⅱ.扫描整个数组,从链指针字段为0的数组元素中寻找SUM字段最大的数组元素,将这个数组元素的位移量填至上一个最大元素的LINK字段,并将1送至这个数组元素的LINK字段。
Ⅲ.重复执行步骤Ⅱ,最后剩下一个链指针字段值为1的数组元素,该元素是链表的链尾。
③按名次(总成绩由高到低的顺序)输出学生信息,也就是按链表中元素的顺序访问其数据元素。
步骤如下:
Ⅰ.将链表的头元素的位移量送到BX寄存器。
Ⅱ.输出BX指向的数据元素的信息,即学号、姓名、语文成绩、数学成绩和总成绩,输出回车换行。
判断[BX].LINK字段的值是否为1,为1则结束程序,否则将该元素LINK字段的内容送入BX中,重复步骤Ⅱ。
4.流程图与关键代码分析:
①按学生总成绩排序(降序)流程图,同时建立单链表:
②按名次由高到低输出学生成绩信息子程序(即单链表方式顺序输出):
5.总结与体会:
(1)程序主要完成功能:
①从键盘输入学生成绩信息,依次将学生的学号、姓名、语文成绩、数学成绩、总成绩(经过计算后),存放在对应数组元素的字段中。
②按照总成绩从高到低排序,即完成单链表的建立,将单链表的头指针保存在DX寄存器中,在输出时从头指针开始遍历单链表。
③按照学生总成绩的名次顺序(由高到低)输出学生成绩信息,即对②所建立的单链表的遍历,在初始时需要将单链表头指针(DX寄存器中存放)赋值给BX,以便完成遍历输出。
(2)程序的实现:
①主要采用了结构数组,因为每一个学生数据项都具有相同的结构,因此先定义一个STUDENT类型的结构体,使用该结构体名作为伪操作指令定义n个相同的结构体类型的数组元素。
在每一个数组元素中都包含一个LINK字段,初始值为0。
②建立单链表,即完成对学生成绩信息的降序排列。
首先从所有数组元素中找出总成绩最大的一项,将该数组元素作为单链表的头指针,保存在DX中,同时将LINK字段赋值为1;
其次,从LINK字段为0的数组元素中找到总成绩最大的一项,将该数组元素的偏移地址作为前一节点的LINK字段值,同时将该节点的LINK字段值置为1;
重复上述步骤直到该结构体类型数组中的最后一个节点LINK字段置为1,该节点即为单链表的链尾。
③遍历单链表,即对学生成绩信息按总成绩由高到低输出。
首先将单链表的头指针赋值给BX,依次循环COUNT(学生人数)次输出每一个数组元素的值,每次输出结束后,将BX的值加上TYPES_ARRAY(即加16字节),BX指向下一个数组元素的首地址。
其次在输出每一个数组元素后,即循环的过程中必须同时满足两个条件:
计数器CX!
=0且[BX].LINK!
=1,若有任意一个条件不满足则跳出循环。
使用LOOPNZ指令即可实现。
④对于将学生成绩信息保存到文件,以及从文件中读取学生成绩信息并输出,关于文件的打开、读取、写入、关闭,这一块相关功能并没有实现。
⑤程序纠错功能较差,当用户输入错误后,没办法实现退格删除,重新输入,有待改进。
⑥由于学生的姓名不定长,导致输出时对齐存在一定困难。
⑦程序还可以继续优化,结合子程序与宏各自的优点,宏的调用速度块,可以用实元代替哑元的方式完成调用不同的子程序,以及灵活的传值,而子程序应该做到可以被多次调用,写的更为灵活、复用性高。
(3)收获和体会:
通过本次综合实验不仅提高了汇编语言程序设计的能力,也对高级汇编技术有了初步的认识与了解,如子程序与宏的配合使用。
同时对于程序的算法,才是程序的核心,是程序设计的重点,根据对程序中数据的分析,采取不同的数据结构,结合优良的算法,可以大大提高程序的效率。
对自己在以后的学习中更应该重视基础、把握重点,编程语言是工具,而算法、结构才是核心。
只有结合良好的思想指导,熟悉利用工具才能做出好的软件。
源代码:
CRLFMACRO;回车换行宏定义
MOVDL,0DH
MOVAH,02H
INT21H
MOVDL,0AH
INT21H
ENDM
BLANKMACRONUM;空格宏定义
MOVCX,NUM
CALLBLANK_PROC
ENDM
SHOWMACROSTRING;显示字符串宏定义
LEADX,STRING
MOVAH,09H
INT21H
ENDM
STUDENTSTRUC;定义学生结构体
LINKDW0;指针,指向下一个节点
IDDB'000';学号
NAMESDB'$$$$$$$$';姓名
CSCOREDB?
;语文成绩
MSCOREDB?
;数学成绩
SUMDB?
;总分
STUDENTENDS
DATASGSEGMENT
DW?
;避免数组元素和LINK字段冲突
S_ARRAYSTUDENT4DUP(<>);预设学生人数
NUMBERDW0;键盘输入学生人数
COUNTEQULENGTHS_ARRAY
;COUNTEQUNUMBER;定义学生人数个数COUNT
;==================菜单=======================
MENU1DB0DH,0AH,0DH,0AH,0DH,0AH,0DH,0AH,0DH,0AH
DB"------------------MENU(LoadORCreate)---------------------",0DH,0AH,0D,0AH
DB"1.Loadthestudentinformationfromanexistingfile(L)",0DH,0AH,0D,0AH
DB"2.Createanewfileandwritethestudentinformation(C)",0DH,0AH,0D,0AH
DB"3.Exitthestudentachievementmanagementsystem(E)",0DH,0AH,0D,0AH
DB"-----------------------------------------------------------",0DH,0AH,0D,0AH
DB"PleaseInputYourChoice:
",'$'
MENU2DB0DH,0AH,0DH,0AH,0DH,0AH,0DH,0AH,0DH,0AH
DB"------------MENU(Display)--------------",0DH,0AH,0DH,0AH
DB"1.SortbystudentID",0DH,0AH,0DH,0AH
DB"2.Sortbyscores",0DH,0AH,0DH,0AH
DB"3.Backtopreviousmenu",0DH,0AH,0DH,0AH
DB"---------------------------------------",0DH,0AH,0DH,0AH
DB"Pleaseinputyourchioce:
",'$'
PRESS_KEYdb0dh,0ah,'Pleasepressanykeytocontinue...','$'
INPUT_NUMBERdb'Pleaseinputthenumberofstudents:
','$'
INPUT_INFOdb0Dh,0Ah,'IDNAMEChineseMath',0Dh,0Ah,0Dh,0Ah,'$'
OUTPUT_INFOdb'IDNAMEChineseMathSUM',0dh,0ah,0Dh,0Ah,'$'
;================菜单定义结束===============
DATASGENDS
STACKSGSEGMENT
DW200DUP(?
)
STACKSGENDS
CODESGSEGMENT
ASSUMECS:
CODESG,DS:
DATASG,SS:
STACKSG
START:
MOVAX,DATASG
MOVDS,AX
MOVAX,STACKSG
MOVSS,AX
MOVSP,200
;=============输出菜单1==================
MAIN_MENU1:
MOVAX,0003H;清屏
INT10H
SHOWMENU1;输出菜单1
MOVAH,01H
INT21H
XORAH,AH
CMPAX,'L'
;JZ_LODEFILE;暂时不做处理
CMPAX,'C'
JZCALL_INPUT
CMPAX,'E'
JZENDPROC
CMPAX,'1'
;JZ_LODEFILE;暂时不做处理
CMPAX,'2'
JZCALL_INPUT
CMPAX,'3'
JZENDPROC
JMPMAIN_MENU1
;=============输出菜单2=================
MAIN_MENU2:
MOVAX,0003H;清屏
INT10H
SHOWMENU2;输出菜单2
MOVAH,01H
INT21H
XORAH,AH
CMPAX,'1'
;JZCALL_OUTPUT1;学号排序暂时不做处理
CMPAX,'2'
JZCALL_OUTPUT2;按总分排序
CMPAX,'3'
JZMAIN_MENU1
JMPMAIN_MENU2
;输入3位学号、姓名、语文、数学成绩,并计算总成绩,其中输入姓名、成绩以空格结束
CALL_INPUT:
MOVAX,0003H;清屏
INT10H
SHOWINPUT_NUMBER
MOVAH,1
INT21H
SUBAL,30H
XORAH,AH
MOVNUMBER,AX
CRLF
SHOWINPUT_INFO
CALLINPUT
JMPMAIN_MENU2
;按学号由小到大进行输出(先进行按学号由小到大排序)
CALL_OUTPUT1:
;按总分由大到小进行输出(先进行按总分由大到小排序)
CALL_OUTPUT2:
MOVAX,0003H;清屏
INT10H
SHOWOUTPUT_INFO
CALLSORT_SCORE
CALLOUTPUT
SHOWPRESS_KEY
MOVAH,01H
INT21H
JMPMAIN_MENU2
ENDPROC:
MOVAH,4CH
INT21H
;===============输入学生成绩信息子程序===============
INPUTPROCNEAR
PUSHAX
PUSHBX
PUSHCX
PUSHDX
PUSHDI
MOVBX,OFFSETS_ARRAY
MOVCX,COUNT
LOOP11:
PUSHCX
MOVDI,00H
MOVCX,03H
LOOP12:
MOVAH,01H
INT21H
MOV[BX].ID[DI],AL;输入学号
INCDI
LOOPLOOP12
BLANK03H
MOVDI,00H
MOVCX,06H
LOOP13:
MOVAH,01H
INT21H
CMPAL,''
JZNEXT
MOV[BX].NAMES[DI],AL;输入姓名
INCDI
LOOPLOOP13
NEXT:
BLANK04H
CALLINPUTGRADE
MOV[BX].CSCORE,DH
BLANK08H
CALLINPUTGRADE
MOV[BX].MSCORE,DH
ADDDH,[BX].CSCORE;计算总分
MOV[BX].SUM,DH
CRLF
ADDBX,TYPES_ARRAY;地址增加一个结构的大小
POPCX
LOOPLOOP11
POPDI
POPDX
POPCX
POPBX
POPAX
RET
INPUTENDP
;================按总分排序子程序2,由高到低===================
SORT_SCOREPROCNEAR
PUSHAX
PUSHBX
PUSHCX
PUSHSI
PUSHDI
MOVCX,COUNT
LOOP21:
PUSHCX
MOVCX,COUNT
MOVBX,OFFSETS_ARRAY
MOVAL,0
LOOP22:
CMP[BX].LINK,0
JNZL21
CMPAL,[BX].SUM
JAEL21
MOVAL,[BX].SUM
MOVDI,BX;将总分最高的学生地址保存在DI中
L21:
ADDBX,TYPES_ARRAY
LOOPLOOP22
POPCX
CMPCX,LENGTHS_ARRAY
JNEL22
MOVDX,DI;总分较高的学生的地址保存在DX中
JMPL23
L22:
MOV[SI].LINK,DI
L23:
MOVSI,DI
MOV[SI].LINK,1;表明该节点已经比较过
LOOPLOOP21
POPDI
POPSI
POPCX
POPBX
POPAX
RET
SORT_SCOREENDP
;===============输出子程序,按单链表方式=================
OUTPUTPROCNEAR;DX中存放头指针,将头指针赋值BX
PUSHAX
PUSHBX
PUSHCX
PUSHSI
MOVBX,DX
MOVCX,COUNT
LOOP31:
PUSHCX
MOVSI,0
MOVCX,3
LOOP32:
MOVDL,[BX].ID[SI];输出学号
MOVAH,02H
INT21H
INCSI
LOOPLOOP32
BLANK03H
MOVSI,0
NEXT1:
MOVAH,02H
MOVDL,[BX].NAMES[SI];输出姓名
CMPDL,'$'
JZNEXT2
INT21H
INCSI
JMPNEXT1
NEXT2:
BLANK04H
MOVDH,[BX].CSCORE
CALLPRINTGRADE;输出语文成绩
BLANK08H
MOVDH,[BX].MSCORE
CALLPRINTGRADE;输出数学成绩
BLANK05H
MOVDH,[BX].SUM
CALLPRINTGRADE;输出总成绩
CRLF
CMP[BX].LINK,1;指针为1表明为链表最后一个节点,跳出循环
MOVAX,[BX].LINK
MOVBX,AX
POPCX
LOOPNZLOOP31
POPSI
POPCX
POPBX
POPAX
RET
OUTPUTENDP
;===================输出空格子程序===================
BLANK_PROCPROCNEAR
LP1:
MOVDL,20H
MOVAH,02H
INT21H
LOOPLP1
RET
BLANK_PROCENDP
;=============输入成绩,将十进制转换为二进制=========
INPUTGRADEPROCNEAR
PUSHCX
PUSHBX
MOVCX,4
MOVDH,0
LOOP41:
MOVAH,01H
INT21H
CMPAL,''
JELP41
SUBAL,30H
MOVBH,AL
MOVBL,10
MOVAL,DH
MULBL
ADDAL,BH