第一次汇编大作业-学生信息统计,包括排序

插入排序,只对哈希表中的序号进行排序,学生信息直接按顺序存入内存,输出排序结果时,按哈希表中的序号进行输出

 

 

 

 

;begin: 2009年 12月 01日 星期二 13:10:06 CST
;end:2009年 12月 03日 星期四 22:34:37 CST
;author: guozan-scst-bupt
;description:students' score record, include student's number/name/score
;comment:不应该想那么多奇怪的方法,反而在汇编里面变的很麻烦,代码长度急剧上升

MAX_NUM    equ    10   


;打印换行
nextline    macro
    push    dx
    push    ax
   
    mov    dl, 0ah
    mov    ah, 2
    int    21h

    pop    ax
    pop    dx
endm

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

dseg    segment
    num    db    MAX_NUM dup (30, 0, 30 dup (0))
    names    db    MAX_NUM dup (30, 0, 30 dup (0))
    sco_int    db    MAX_NUM dup (0)
    sco_dec    db    MAX_NUM dup (0)
    sum_int    dw    0
    sum_dec    dw    0
   
    hash    db    MAX_NUM dup (0)

    welcome         db      'Welcome to this program! Created by guozan!$'  ;进入程序的提示信息
    ask_total       db      'Please enter the total number of students:$'   ;学生总人数
    ask_number      db      'Please enter the number:$'     ;询问学号
    ask_name        db      'Please enter the name, support english only:$' ;询问姓名,英语的名字
    ask_score       db      'Please enter the score, decimal is one:$'      ;询问成绩,精确到小数点后一位
    exit_info       db      'Succeed exit!$'
dseg    ends

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

;*****************************************************************


cseg    segment
    assume    cs:cseg, ds:dseg
start:
    mov    ax, dseg
    mov    ds, ax

;输出欢迎信息
    lea    dx, welcome
    mov    ah, 09h
    int    21h
    nextline

;ask_total
    lea    dx, ask_total
    mov    ah, 09h
    int    21h
;get total
    mov    ah, 1
    int    21h
    sub    al, '0'
    mov    cl, al    ;将数目放入cl
    xor    ch, ch    ;cx决定读入的数据放入哪个位置
    nextline
    push    cx    ;保存总共的个数,方便打印,print和排序时使用

get_input:
    or    cx, cx
    jz    print   
    mov    ax, cx    ;bx = (cx-1) * 32;用于以后往内存存数据用;倒着存的
    dec    ax
    mov    bx, 32    ;30 + 1 + 1
    mul    bx
    mov    bx, ax    ;bx 中是偏移量
;读入三个信息
;********************************************************
;please enter number
    lea    dx, ask_number
    mov    ah, 09h
    int    21h
;get the num
    lea    dx, num
    add    dx, bx    ;
    mov    ah, 0ah
    int    21h
    nextline

    push    bx    ;103

    mov    bx, dx    ;这次读如的地址,方便下面在尾部加上$
    xor    ah, ah
    mov    al, [bx + 1]    ;把读入的字符数目放入Ax
    add    dx, 2    ;移动到字符数目位置后面一位
    add    dx, ax    ;移动到最后一个字符后面
    mov    al, '$'    ;结尾符
    mov    bx, dx   
    mov    [bx], al    ;植入结尾

;---------------------------------------
;pleas enter name
    lea    dx, ask_name
    mov    ah, 09h
    int    21h
;get the name
    pop    bx    ;87

    lea    dx, names
    add    dx, bx    ;bx中是偏移量,来自enternumber
    mov    ah, 0ah
    int    21h
    nextline

    mov    bx, dx
    xor    ah, ah
    mov    al, [bx + 1]    ;把读入的字符数目放入Ax
    add    dx, 2    ;移动到字符数目位置后面一位
    add    dx, ax    ;移动到最后一个字符后面
    mov    al, '$'    ;结尾符
    mov    bx, dx   
    mov    [bx], al    ;植入结尾

;---------------------------------------
;please enter score
    lea    dx, ask_score
    mov    ah, 09h
    int    21h
;get the score
    mov    dx, 0    ;dx 里存的是和,所以先清0
get_int:
    mov    ah, 1
    int    21h
    cmp    al, '.'
    jz    get_deci
    sub    al, '0'
    xor    ah, ah
    push    ax   
    ;读入了一个数,然后dx*10 + al,结果存储在dx中,存的就是一个数
    mov    ax, dx    ;ax = dx
    mov    bl, 10
    mul    bl    ;ax = ax * 10
    pop    dx    ;dx = old_ax, 读入的那个al
    add    dx, ax    ;dx = old_ax + ax(dx) * 10

    jmp    get_int

get_deci:
    mov    ax, dx    ;把计算出的结果转移一下
    lea    dx, sco_int    ;dx = sco_int + cx - 1
    mov    bx, cx
    dec    bx    ;存储的偏移量
    add    bx, dx    ;这次的整数放的位置
    mov    [bx],al    ;把整数部分存入内存

    xor    ah, ah
    push    ax    ;把整数部分放入堆栈,保存一下,方便下面的排序

    ;add to sum_int
    lea    bx, sum_int
    mov    dx, [bx]
    add    ax, dx    ;sum_int + 这次的读入的整数
    mov    [bx], ax    ;结果存入内存

    ;读入小数部分,一位
    mov    ah, 1
    int    21h
    sub    al, '0'
    xor    ah, ah

    lea    dx, sco_dec   
    mov    bx, cx
    dec    bx    ;计算出偏移量
    add    bx, dx    ;算出此次存储地址;bx可以用整数时用的,不用改
    xor    ah, ah
    mov    [bx], al    ;小数部分存入内存

    push    ax    ;小数部分压入堆栈

    ;add deci to sum_dec
    lea    bx, sum_dec
    mov    dx, [bx]    ;读出来数据
    add    ax, dx    ;加上此次读入的小数部分
    mov    [bx], ax    ;放回内存

    mov    ah, 1
    int    21h    ;读一个回车,提高用户体验
    ;nextline

;--------------------------------------------------------
;使用hash表去标记,hash中的存的只是排序后此项在num,name数组中的位置
insert:

    pop    ax    ;小数部分
    pop    dx    ;整数部分
    pop    bx    ;取出输入的数据总数,从初始第一次push 的cx中读出来的
    push    bx    ;重新放回

    call     insert_table
       
    ;lea    bx, hash    ;为修改hash中的数据做准备,得到首地址
    ;mov    ax, cx    ;[bx + cx - 1] = cx - 1
    ;dec    ax
    ;add    bx, ax
    ;mov    [bx], al
   
    ;test ok, get the total number of input, and then give it back
    ;pop    dx
    ;push    dx
    ;nextline
    ;add    dx, '0'
    ;mov    ah, 2
    ;int    21h
    ;nextline
    ;call     insert_table


;-----------------------------------------------------
    dec    cx    ;循环控制
    jmp    get_input    ;进入下一个读入循环
;***************************************************


print:
;打印平均
    lea    bx, sum_int    ;整数部分的和
    mov    ax, [bx]
    pop    cx    ;总共的数目,来自于第一个push,刚读入总数的时候
    push    cx    ;保存cx
    div    cl    ;除法,求平均
    push    ax    ;保存除的结果
   
    mov    al, ah    ;把余数转移
    xor    ah, ah
    xor    bh, bh
    mov    bl, 10
    mul    bl    ;ax = al * 10

    lea    bx, sum_dec    ;小数部分的和
    mov    dx, [bx]
    add    ax, dx    ;整数的余数 * 10 + 小数部分,得到新的小数部分
    div    cl
    xor    ah, ah    ;小数部分求平均,只保存商,余数丢弃
   
    xor    bh, bh
    mov    bl, 10
    div    bl    ;ax / 10,商可能太大,需要向高位进位
    mov    bl, al    ;商转移到bx
    mov    al, ah    ;余数放到ax,也就是小数位
    xor    ah, ah
    pop    dx    ;把整数除的结果弹出来
    add    dx, bx    ;把小数部分的进位加上
   
    push    ax    ;存小数
    mov    ax, dx    ;打印整数部分
    xor    ah, ah    ;把余数清掉
    call    print_num

    mov    dl, '.'
    mov    ah, 2
    int    21h    ;打印小数点

    pop    ax    ;打印小数
    call    print_num
    nextline

    lea    bx, hash    ;哈希表的首地址
    pop    cx    ;
print_loop:
    push    bx    ;地址保存,因为循环里面用到了bx

    xor    dh, dh
    mov    dl, [bx]    ;dx标记此次要输出的数据的地址,这时还只是标号
    push    dx    ;把序号保存,打印成绩的时候用
    ;sub    dx, '0'
    ;dx = dx * 32 + num[hash[i]]
    ;计算出偏移量,放在ax中,打印学号和名字时使用
    mov    ax, 32
    mul    dx
    push    ax    ;保存偏移量,name num的偏移量都是ax

    ;输出学号
    lea    dx, num
    add    ax, 2    ;+ 2,前方有总数和读入数目
    add    dx, ax    ;偏移地址
    mov    ah, 09h
    int    21h
    mov    dl, ' '    ;空格
    mov    ah, 2
    int    21h

    ;输出姓名
    pop    ax    ;偏移量
    lea    dx, names
    add    ax, 2
    add    dx, ax
    mov    ah, 09h
    int    21h
    mov     dl, ' ';空格
    mov     ah, 2
    int     21h

    ;输出成绩
    ;整数部分
    lea    bx, sco_int
    pop    ax    ;序号
    push    ax    ;方便小数部分使用
    add    bx, ax    ;偏移后的位置,成绩所在位置
    mov    al, [bx]    ;把当前位置的成绩当作参数,call print_num,输出道屏幕
    call    print_num

    ;小数点
    mov    dl, '.'
    mov    ah, 2
    int    21h

    ;小数部分
    lea    bx, sco_dec
    pop    ax
    add    bx, ax
    mov    al, [bx]
    call    print_num

    nextline
    pop    bx
    inc    bx
    loop    print_loop
exit:   
    lea    dx, exit_info
    mov    ah, 09h
    int    21h
    mov    ah, 4ch
    int    21h


;要打印的数放到ax中,成绩不可能大于100
print_num    proc    near
    push    ax
    push    bx
    push    cx
    push    dx
   
    mov    cx, 0    ;特殊用途,标记百位是不是1,默认是0

hundred:    ;百位
    mov    bl, 100
    div    bl
    push    ax    ;保存相除的结果
    or    al, al    ;看商是否是0
    jz    deca    ;百位是0,不用打印,处理余数,剩下的十位和个位

    mov    dl, al    ;打印字符,商
    add    dl, '0'
    mov    ah, 2
    int    21h

    mov    cx, 1    ;标记有百位

deca:    ;十位
    pop    ax    ;读出相除的结果
    mov    al, ah    ;把余数当作被除数
    xor    ah, ah
    mov    bl, 10
    div    bl
    push    ax    ;保存相除的结果

    or    cx, cx    ;检查百位是否是0,是0,可以不打印十位的0,是1,必须打印0
    jnz    print_deca    ;无条件打印十位
    or    al, al
    jz    over    ;十位是0,不用打印

print_deca:    ;无条件打印十位
    mov    dl, al    ;打印商
    add    dl, '0'
    mov    ah, 2
    int    21h

over:    ;个位,无条件必须打印
    pop    ax    ;读出相除的结果
    mov    dl, ah    ;把余数放到 dl 中打印
    add    dl, '0'
    mov    ah, 2
    int    21h
   
    pop    dx
    pop    cx
    pop    bx
    pop    ax

    ret
print_num    endp

;分析数据,然后放入数据hash表
insert_table    proc    ;序列号就是偏移量,放入table中的是序列号
    push    ax    ;小数部分
    push    bx    ;总共输入的数量
    push    cx    ;当前输入的第几个,倒着的5,4,3,2,1
    push    dx    ;整数部分

;找到要比较的原串
    lea    di, hash
    add    di, bx    ;当前整数部分数组末尾处的偏移量
    dec    di    ;末尾处
cmp_int:
    cmp    bx, cx    ;比较到了哪一个,如果到了自己,也就是bx-到正好是要输入的那个,放入
    je    put_in

    lea    si, sco_int    ;整数部分的地址
    push    ax
    mov    ax, [di]    ;di中一次取出来两个字节,需要转换一下
    xor    ah, ah
    add    si, ax
    pop    ax
    ;add    si, [di];取出了两个字节    ;取出当前hash位置存放的序号,然后加上si,得到这次的整数的位置
    cmp    dl, [si]    ;整数部分和当前位置的整数部分比较,貌似这样就会只取出来一个字符
    jl    mov_space    ;新来的比较小,放入这个位置,把这个位置移出来
    je    cmp_dec    ;整数相同,比较小数部分
    dec    bx    ;正在比较的是bx
    dec    di
    jmp    cmp_int

cmp_dec:
    push    ax
    lea    si, sco_dec
    mov    ax, [di]
    xor    ah, ah
    add    si, ax    ;小数存储的物理地址
    pop    ax

    cmp    al, [si]
    jle    mov_space    ;相等或比较小,放入这个位置

    dec    bx    ;正在比较的是bx
    dec    di
    jmp    cmp_int    ;比较大,接着比较

mov_space:
    lea    si, hash    ;从hash的头部开始移动
    mov    dx, 1
loop1:
    mov    al, [si+1]
    mov    [si], al    ;[si] = [si + 1]
    inc    si

    dec    bx
    cmp    bx, dx    ;如果等于1,就是说总共移动了bx - 1次
    je    put_in
    jmp    loop1

put_in:
    dec    cx
    mov    [di], cl
   

    pop    dx
    pop    cx
    pop    bx
    pop    ax

    ret
insert_table    endp
cseg    ends
    end    start

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值