8086汇编:快速排序

代码以及详细注释:

.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
 
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CCF小彤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值