组装 - 用于排序字符串的冒泡排序
Posted
技术标签:
【中文标题】组装 - 用于排序字符串的冒泡排序【英文标题】:Assembly - bubble sort for sorting string 【发布时间】:2014-12-06 17:20:27 【问题描述】:我正在使用 tasm 编写一个汇编程序。我的任务是编写一个程序,该程序将使用冒泡排序按字母顺序对输入的字符串进行排序。前任。如果你输入“hello”,它应该写成“ehllo”。我已经写了输入字符串并对其进行排序的乞求(我认为它可以正常工作,直到它应该打印出结果的最后,但最后它只写了我的 .data 一次并完成了它的工作)PS 抱歉不好英文
.model small
.stack 100h
.data
request db 'This program is using bubblesort to get alphabetical order of your enterd string', 0Dh, 0Ah, 'Enter your string:', 0Dh, 0Ah, '$'
result db 0Dh, 0Ah, 'Result:', 0Dh, 0Ah, '$'
buffer db 100, ?, 100 dup (0)
.code
start:
MOV ax, @data
MOV ds, ax
MOV ah, 09h
MOV dx, offset request
int 21h
MOV dx, offset buffer
MOV ah, 0Ah
INT 21h
MOV si, offset buffer
INC si
MOV bh, [si]
INC si
sort:
mov cx, [si]
mov bx, [si]
nextelement:
mov ax, [bx+si]
cmp ax, [bx+si+1]
jge noswap
xchg ax, [bx+si+1]
mov ax, [bx+si]
noswap:
inc si
cmp cx, si
jl nextelement
loop nextelement
MOV ah, 09h
MOV dx, offset result
int 21h
char:
LODSB
MOV ah, 2
MOV dl, al
INT 21h
DEC bh
JZ ending
JMP char
ending:
MOV ax, 4c00h
INT 21h
end start
【问题讨论】:
请注意,bh 寄存器与 bx 共享高 8 位,因此如果加载后者,前者也会被覆盖。 好吧,我以后会记住的 【参考方案1】:1) 对于冒泡排序,您需要两个嵌套循环。外层循环重置内层循环的起始参数,直到没有东西可以交换。
2) 您对字符进行排序。那是 8 位值(字节)。您不能将它们直接加载到 16 位寄存器 (mov ax, [bx+si]
)。
3) [bx+si]
& [bx+si+1]
: 这太错误了,我无法解释错误:-)。
我没有更正您的代码,而是“从头开始”编写了一个示例:按照http://en.wikipedia.org/wiki/Bubble_sort 中的插图:
.MODEL small
.STACK 1000h ; Don't skimp with stack!
.DATA
Struct0A EQU $ ; Buffer for INT 21h/0Ah (max,got,buf)
max db 100 ; Maximum characters buffer can hold (incl. CR (0Dh))
got db 0 ; Number of characters actually read, (excl. CR (0Dh))
buf db 100 dup (0) ; Actual characters read, including the final carriage return (0Dh)
Linefeed db 13, 10, '$'
GetString db 'Enter string: $'
.CODE
start:
mov ax, @DATA ; Initialize DS
mov ds, ax
; Input String
mov ah, 09h
mov dx, OFFSET GetString
int 21h
mov dx, OFFSET Struct0A
mov ah, 0Ah
INT 21h
mov si, OFFSET buf ; Base for [si + bx]
xor bx, bx ; Prepare BX for following byte load
mov bl, got ; Load length of string = 0Dh at the end
mov BYTE PTR [si + bx], '$' ; Delimiter for int 21h / 09h
outer:
dec bx ; The last character is already at the right place
jz done ; No characters left = done
mov cx, bx ; CX: loop variable
mov si, OFFSET buf
xor dl, dl ; DL (hasSwapped) = false
inner:
mov ax, [si] ; Load **two** characters
cmp al, ah ; AL: 1. char, AH: 2. char
jbe S1 ; AL <= AH - no change
mov dl, 1 ; hasSwapped = true
xchg al, ah ; Swap characters
mov [si], ax ; Store swapped characters
S1:
inc si ; Next pair of characters
loop inner
test dl, dl ; hasSwapped == true?
jnz outer ; yes: once more
done:
; Print result
mov dx, OFFSET Linefeed
mov ah, 09h
int 21h
mov dx, OFFSET buf
mov ah, 09h
int 21h
mov ax, 4C00h
int 21h
END start
这是另一个“动画”插图:
https://www.youtube.com/watch?v=lyZQPjUT5B4
【讨论】:
非常感谢您的帮助。我了解冒泡排序的外观以及如何用其他语言对其进行编程,只是我真的不了解汇编程序。也感谢您花时间编写完整的程序:) 在某些 CPU 上,通过始终交换并使存储有条件来避免缓存行拆分/未对齐加载可能是一种胜利。例如mov al, [si]
/rol ax,8
/cmp/jbe
。你甚至可以使用lodsb
(但在比mov
/inc
慢的现代CPU上)。这会在 AX 上创建循环携带的依赖关系,但是如果需要大量交换,则 OTOH 会避免从存储到部分重叠负载的存储转发停顿。但是首先使用冒泡排序的唯一原因是紧凑的代码大小,而不是性能,所以我不会过多抱怨使用缓慢的 loop
指令。
@PeterCordes :如果定位 8086 rol ax, 8
不可用。
@PeterCordes : 如果你好奇当你推送一个立即数时 TASM 默认会发生什么,这是它生成的代码类型:push ax
push bp
mov bp, sp
mov word ptr [bp+2], 33h
@987654340如果使用了指令push 33h
,则会生成@。如果他们从不调试代码或生成列表文件,大多数人都不会意识到这一点。如果文件中没有指令或命令行上没有覆盖,TASM 将静默进行这些类型的转换,因为它默认为 8086 代码生成。
@PeterCordes :不确定是否有办法在 TASM 中关闭它。在使用 TASM 进行开发并针对实模式代码而不指定 .186
或更高版本时,我始终牢记这一点。另一方面,如果您在针对 8086 时尝试使用不受支持的指令而不是静默生成等效代码,则 MASM 将出错。以上是关于组装 - 用于排序字符串的冒泡排序的主要内容,如果未能解决你的问题,请参考以下文章