代码以及详细注释:
.model small ; 小型存储模式
.stack ; 定义堆栈段
.data
start_str db 'QuickSort start...' , 0dh, 0ah, '$'
end_str db 'QuickSort ok! They are sorted in a non-decreacing order:' , 0dh, 0ah, '->' , '$'
input_str db 'Please input a list of numbers(one number per line, finish with a blank line):' , 0dh, 0ah, '$'
initial_str db 'The initial numbers: ' , 0dh, 0ah, '->' , '$'
buf db 32 dup( ?)
buf2 db 16, ?, 16 dup( ?)
ary db 256 dup( ?) ; [ num_len] [ interger_len] [ num] ,例:5 3 123.21
tbl dw 16 dup( ?) ; 索引表,最多16个数
tmp dw ?
cnt dw ?
l dw 0
r dw ?
.code
main proc
start:
mov ax, @data
mov ds, ax
mov es, ax ; 附加段地址
call input_data
lea dx, initial_str
mov ah, 9
int 21h
call output_ary_elem
lea dx, start_str
int 21h
call quicksort
lea dx, end_str
int 21h
call output_ary_elem
exit:
mov ah, 4ch ; 带返回码结束
int 21h ; 调用中断,返回
; == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; 从键盘接收多组数据输入到ary数组,并更新tbl表,cnt, l, r值
; (各数字用换行隔开)
; (输入空行结束输入)
; == == == == == == == == == == == == == == == == == == == == == == == == == == ==
input_data proc
push di
push ax
push bx
push cx
push dx
xor cx, cx
xor bx, bx
lea dx, input_str
mov ah, 9
int 21h
lea di, ary ; 取数组首地址
store_again:
mov tbl[ bx] , di
add bx, 2
inc cx
mov ax, di ; 如果存储前后首地址相同,说明键入了空行,结束
call store_decimal_fun
cmp ax, di
jne store_again
dec cx
mov cnt, cx
dec cx
mov r, cx
; ; 输出cnt和r
; mov ah, 02h
; mov dx, cnt
; add dl, 30h
; int 21h
; call print_crlf
; mov dx, r
; add dl, 30h
; int 21h
; call print_crlf
pop dx
pop cx
pop bx
pop ax
pop di
ret
input_data endp
; == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
; di存该数在数组中地址,从键盘接收到一个十进制小数存到( di) 为首地址的空间
; 本函数可以自动格式化输入( 如0.0-> 0; 000123.12300-> 123.123; .2-> 0.2) ,但是无法纠错
; return: 返回数组下个元素首地址,存到di
; == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
store_decimal_fun proc
push ax
push dx
push si
push bx
push cx
xor cx, cx
mov ah, 0ah ; 从键盘接收小数存到buf2
lea dx, buf2
int 21h
mov cl, buf2[ 1] ; 把串长存到cl
cmp cl, 0
je end_decimal_store
; == == == == == == == == == == == == == == == == == == == ==
; 如果整数部分不为0,去除前面的0
; == == == == == == == == == == == == == == == == == == == ==
cld
push di
; 去除数字前面的0
lea di, buf2[ 2]
mov al, '0'
repe scasb ; di
; 修正cl和di,cl多减了1,di多加了1
inc cl
dec di
mov si, di ; buf2第一个非零元素地址
mov al, [ di]
cmp al, '.' ; 如果.前面只有0或没有数字,需规范为一个0
jne end_add_zero
dec di
dec si
mov al, '0'
mov [ di] , al
inc cl ; 数字个数加1
end_add_zero:
; == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
; 寻找'.' ,并设置整数长度
; == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
push cx
push di
mov al, '.'
repne scasb
mov bx, di ; 暂存末尾地址
dec bx
sub di, si
cmp cx, 0 ; 如果没找到'.' ,则全是整数,不需要去除小数部分的0
jne have_point
; == == == == == == == == == == == == =
; 如果最后一位是'.' ,将其去除
mov ax, [ bx]
cmp al, '.'
jne no_point
dec di
mov word ptr tmp, di ; 把整数部分长度暂存到tmp
pop di ; 恢复现场
pop cx
jmp remove_point
; == == == == == == == == == == == == =
no_point:
mov word ptr tmp, di ; 把整数部分长度暂存到tmp
pop di ; 恢复现场
pop cx
jmp end_find
have_point:
dec di ; 找到'.' 修正di
mov word ptr tmp, di ; 把整数部分长度暂存到tmp
pop di ; 恢复现场
pop cx
; == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
; 如果是小数,去除数字后面的0
std ; 从后往前扫描
add di, cx
dec di ; 最后元素地址
mov al, '0'
repe scasb ; 清除后面的0
; 修正cl, di:cl, di都多减了1
inc cl
inc di
; 如果最后一位只剩下了'.' ,则直接清除
mov ax, [ di]
cmp al, '.'
jne end_find
remove_point:
dec cl
end_find:
pop di ; ary元素首地址
push di
; == == == == == == == == == == == == == == == == == == == ==
mov [ di] , cl ; 更新串长
inc di
mov al, byte ptr tmp
mov [ di] , al ; 更新整数部分长度
inc di
cld
store_ary:
; 从buf2取数( AL) ←( DS:SI)
lodsb
; 往ary存数( ES:DI) ←( AL)
stosb
loop store_ary
; 把di中原来push进去的元素首地址pop给si
pop si
call print_ary_elem
mov cx, 10
clear_extra_digit:
call print_space
loop clear_extra_digit
call print_crlf
end_decimal_store:
pop cx
pop bx
pop si
pop dx
pop ax
ret
store_decimal_fun endp
; == == == == == == == == == == == == == == == == == == == == == == == =
; cnt中存储数字个数,按tbl表顺序打印所有元素
; == == == == == == == == == == == == == == == == == == == == == == == =
output_ary_elem proc
push cx
push bx
push si
xor bx, bx
mov cx, cnt
cmp cx, 0
je end_output_ary_elem
loop_output_ary_elem:
mov si, tbl[ bx]
call print_ary_elem
call print_space
add bx, 2
loop loop_output_ary_elem
end_output_ary_elem:
call print_crlf
pop si
pop bx
pop cx
ret
output_ary_elem endp
; == == == == == == == == == == == == == == == == == == == == == == == =
; si存数组元素首地址,输出元素
; == == == == == == == == == == == == == == == == == == == == == == == =
print_ary_elem proc
push ax
push cx
push dx
push si
xor cx, cx
mov ah, 02h
mov dl, [ si]
mov cl, dl
cmp cl, 0
je end_print_ary_elem
; add dl, 30h ; 输出总长度
; int 21h
; mov dl, ':'
; int 21h
inc si
; mov dl, [ si]
; add dl, 30h ; 输出整数部分长度
; int 21h
; mov dl, ':'
; int 21h
print_ary_elem1:
inc si
mov dl, [ si]
int 21h
loop print_ary_elem1
end_print_ary_elem:
pop si
pop dx
pop cx
pop ax
ret
print_ary_elem endp
; == == == == == == == == == == == == == == == == == == == == == == == ==
; ary_elem:| 总长度| 整数部分长度| xxx.xxx |
; | 1byte| 1byte | nbyte |
; 比较reg中指向的元素和tbl[ ind_reg] 中指向的元素的大小
; si存左比较数偏移,di存右比较数偏移
; == == == == == == == == == == == == == == == == == == == == == == == ==
ary_elem_cmp MACRO reg, ind_reg
local len_l
local end_ary_elem_cmp
push bx
push si
push di
push ax
push cx
xor cx, cx
mov di, tbl[ ind_reg] ; ind_reg可能为si,这两个mov顺序不能改
mov si, reg
; ; 先比较整数部分长度,长的更大
mov bx, 1
mov ah, byte ptr [ si] [ bx]
mov al, byte ptr [ di] [ bx]
cmp ah, al
jne end_ary_elem_cmp
; ; 整数部分长度相等,进行串比较
; ; DS:[ SI] - ES:[ DI] ;
; ; 设置计数值,为串长最小的那个
mov ah, byte ptr [ si]
mov al, byte ptr [ di]
cmp ah, al
jbe len_l
mov ah, al
len_l:
mov cl, ah
; ; 指向数字部分,开始比较
add si, 2
add di, 2
cld
repe cmpsb
jne end_ary_elem_cmp
; ; 比较过程数字完全相同,则总长度长的更大
cmp ah ,al
end_ary_elem_cmp:
pop cx
pop ax
pop di
pop si
pop bx
ENDM
; == == == == == == == == == == == == == == == == == == == == == == == == == ==
; 快排主函数
; 前条件:
; ( 1) l, r分别存储数组最左下标和最右下标
; ( 2) ary数组需事先存好相应数字
; ( 3) tbl数组需事先存好ary元素的地址
; return: 排好的tbl数组
; == == == == == == == == == == == == == == == == == == == == == == == == == ==
quicksort proc near
push ax
push bx
push cx
push si
push dx
mov ax, l
cmp ax, r
jle continue ; l> r return
jmp over
continue:
xor si, si ; i= 0
xor bx, bx ; j= 0
mov si, l ; i= l
mov bx, r ; j= r
sal si, 1
mov ax, tbl[ si] ; 保存哨兵x= s[ l]
sar si, 1
sort_again:
cmp bx, si ; while ( i!= j)
jne loop_j_again
jmp over_loop
loop_j_again:
cmp si, bx ; while( i< j)
jl next
jmp over_loop ; 跳出主循环
next:
sal bx, 1 ; 因为是字,所以偏移量乘2
ary_elem_cmp ax, bx ; while ( s[ j] >= x)
jg end_loop_j ; 跳出第一个子循环
sar bx, 1 ; 先jg判断,防止移位改变标志位
dec bx ; j--
jmp loop_j_again ; 继续循环
end_loop_j:
mov dx, tbl[ bx] ; jg之前已经左移,无需再次左移
sar bx, 1
sal si, 1
mov tbl[ si] , dx ; s[ i] = s[ j]
sar si, 1
loop_i_again:
cmp si, bx ; while ( i< j)
jge over_loop ; i>= j
sal si, 1
ary_elem_cmp ax, si ; while ( s[ i] <= x)
jl end_loop_i ; x< s[ i]
sar si, 1
inc si ; i++
jmp loop_i_again
end_loop_i:
mov dx, tbl[ si]
sar si, 1
sal bx, 1
mov tbl[ bx] , dx ; s[ j] = s[ i]
sar bx, 1
jmp sort_again
over_loop:
sal si, 1
mov tbl[ si] , ax ; s[ i] = x 填坑
sar si, 1
push si ; push i
push r ; push r
mov r, si
dec r ; r= i-1
call quicksort ; quicksort( l, i-1) ;
pop r
pop bx
mov l, bx
inc l ; l= i+1
call quicksort ; quicksort( i+1, r) ;
over:
pop dx
pop si
pop cx
pop bx
pop ax
ret
quicksort endp
; == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
; 输出换行
; == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
print_crlf proc
push ax
push bx
push dx
mov ah, 02h
mov dx, 0dh
int 21h
mov dx, 0ah
int 21h
pop dx
pop bx
pop ax
ret
print_crlf endp
print_space proc
push ax
push dx
mov ah, 02h
mov dl, 32
int 21h
pop dx
pop ax
ret
print_space endp
; == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
main endp
end start