DATAS SEGMENT DATA DB 24,18,-8,-16,66,56,86,6,10,98 COUNT DB 10,10DATAS ENDSCODES SEGMENT ASSUME CS:CODES,DS:DATAS,ES:DATASSTART: MOV AX,DATAS MOV DS,AX MOV ES,AX MOV BL,1 ;改进版本,用BL来检验是否排序完成,减少循环次数LOOP1: CMP BL,0 JE DATAOUT ;ZF=1,若相等或为0,则跳转XOR BL,BL ;用逻辑异或将BL清零 MOV CL,COUNT ;COUNT用于外层的计数 DEC CL ;CL减一,CL用于内层的计数 PUSH CX ;将CX压入堆栈 LEA DI,DATA ;将数据段首地址赋值给DI LOOP2: MOV AL,[DI] CMP AL,[DI+1] ;将前一个数与后一个数比较 JLE LOOP3 ;ZF=1或SF!=OF 若前一个数小于或等于后一个数,则跳转到LOOP3XCHG [DI+1],AL ;前者大于后者,则交换两数MOV [DI],AL ;如果前一个数字大于后一个数字,则交换 MOV BL,1 LOOP3: INC DI ;指针加一LOOP LOOP2 ;循环L00P2,直到CX==0成立 POP CX ;将CX从堆栈中弹出 MOV COUNT,CL ;改变外层计数器的值 JMP LOOP1 DATAOUT: MOV CL,10 ;开始数据输出 LEA DI,DATA ;载入数据段(数组)首地址 NEXT: MOV AX,0 ;输出下一个数 MOV BH,2 ;输出的数字之间的空格 MOV AL,[DI] ;取数 CMP AL,0 JGE NON ;如果是非负数,则跳至NON NEG AL ;若是负数,将AL中的负数取补转成对应的正数 PUSH AX ;INT 21H 中断将会有一个返回值 MOV AH,2 ;同时显示负数的标记‘-’ MOV DL,'-' ;注意这个时候 AX 的值会因为 21H中断的调用而改变, 所以先要保存起来 INT 21H ;若是负数,在屏幕上显示‘-’号 POP AX ;某些中断之后AX会改变 NON: XOR AH,AH ;将AH清零DIV COUNT+1 ;除以10取十位 MOV DH,AH ;AH是余数,AL是商(如果是个位数,则AL为零) CMP AL,0 JE SINGLE ;如果AL为零(个位数),则跳转到DIR,直接输出十位数 ADD AL,30H ;将数字转换成ASC码 MOV DL,AL ;数字放入DL,在屏幕输出 MOV AH,2 INT 21H ;显示十位上的数值 SINGLE: MOV AL,DH ;将余数(个位数)放入AL XOR AH,AH ;将AH清零 ADD AX,3030H MOV DL,AL ;所以最好在显示时判断是否是大于100或者小于100再根据判断结果来处理 DIV OUTP:MOV AH,2 ;显示输出功能INT 21H ;显示个位数 DEC BH ;BH减一JZ XT ;若相等或为0,则跳转MOV DL,BL ;BL为零,屏幕输出空格 JMP OUTP XT: DEC CL ;输出数组下一个 JZ DONE ;如果ZF标志位为零(CL为零),则程序完成 INC DI ;数组指针+1 JMP NEXT ;继续输出数组下一个数 DONE: MOV AH,1 ;键盘输入并回显功能,目的是使程序输出窗口暂停,以便看到输出结果INT 21H MOV AH,4CH ;带返回码结束功能INT 21H ;返回系统 CODES ENDS END START