【持续更新】汇编实现常见数据结构与算法
【持续更新】汇编实现常见数据结构与算法
0x00 排序
assume cs:code,ds:data,ss:stack
stack segment
db 128 dup (0)
stack ends
data segment
datas dw 10,9,8,7,6,5,4,3,2,1
sizz dw 10
data ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,128
mov ax,data
mov ds,ax
push bp
mov bp,sp
sub sp,6
mov word ptr [bp-6],1
jmp short cmp0
s: mov si,[bp-6]
add si,si
mov ax,datas[si]
mov [bp-2],ax
mov ax,[bp-6]
mov [bp-4],ax
jmp short cmp1
s1: mov si,[bp-4]
add si,si
mov ax,datas[si-2]
mov datas[si],ax
dec word ptr [bp-4]
cmp1: cmp word ptr [bp-4],0
jna fin
mov si,[bp-4]
add si,si
mov ax,datas[si-2]
cmp [bp-2],ax
jnb fin
jmp short s1
fin: mov ax,[bp-2]
mov si,[bp-4]
add si,si
mov datas[si],ax
inc word ptr [bp-6]
cmp0: mov ax,sizz
cmp word ptr [bp-6],ax
jb s
mov ax,4c00h
int 21h
code ends
end start
按照c语言改写的 难度不大 无非是局部变量用栈实现,但第一次写,还是有点手生
上述代码运行结果正确
//2020-7-9补充
帮人写的冒泡 快速 选择 插入 4合1汇编程序,编译通过运行正确,汇编快排我都服了自己了
assume cs:code
;============================================================================
data segment
array db 17,5,6,28,-3,0,-18,37,89,-100;待排序序列
line dw 9;print_num例程 使用,决定第几行输出
message db ' please type 1-4 to chose buble/insert/quick/select sort:',0;print_string的提示消息
wrong db ' you type the wrong key,press any key to exit (=',0
array_back_up db 17,5,6,28,-3,0,-18,37,89,-100;每次排序完成后,由此恢复到array
data ends
;============================================================================
stack segment
db 2048 dup (0)
stack ends
code segment
start: mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
mov sp,256
;清屏幕
call clear_screen
;显示待排序列
mov dh,2
call print_num
;提示输入
mov dh,4
mov si,offset message
call print_string
@@m5: ;以下代码用于恢复待排序列原装,以便多次排序
mov ax,data
mov es,ax
mov si,offset array_back_up
mov di,offset array
mov cx,10
cld
rep movsb
;以下恢复 line的行数
mov line,9
;以下代码用于等待输入并选择对应排序算法
mov ah,0
int 16h;调用键盘输入中断
call clear_screen;清屏
;显示用户输入的ascii
mov bl,al
call type_callback
mov dh,6
mov si,offset message
call print_num;显示提示
;提示输入
mov dh,4
call print_string
cmp al,'0'
je @@m0;调用分隔符
cmp al,'1'
je @@m1;调用冒泡
cmp al,'2'
je @@m2;调用插入
cmp al,'3'
je @@m3;调用快排
cmp al,'4'
je @@m4;调用选择
;显示错误输入
mov dh,8
mov si,offset wrong
call print_string
;等待任意输入exit
mov ah,0
int 16h
mov ax,4c00h
int 21h
@@m0: mov dh,9
call print_num_with_spilt
jmp short @@m5
@@m1: call buble_sort
jmp short @@m5
@@m2: call insert_sort
jmp short @@m5
@@m3: mov ax,0
push ax;传递参数 左边界索引
mov ax,9
push ax;传递参数 右边界索引
call quick_sort
pop ax
pop ax
jmp short @@m5
@@m4: call select_sort
jmp short @@m5
;============================================================================
;清屏例程 无任何参数及返回值
clear_screen:
push ax
push es
push bx
push cx
mov cx,2000
mov ax,0b800h
mov es,ax
mov bx,0
@@c1: mov byte ptr es:[bx],0
add bx,2
loop @@c1
pop cx
pop bx
pop es
pop ax
ret
;============================================================================
;右下角显示用户按下的键 参数 bl为ascii码,非法输入为'!' 无返回值
type_callback:
push ax
push bx
push cx
push es
mov ax,0b800h
mov es,ax
mov es:[3990],bl
mov es:byte ptr [3991],2
pop es
pop cx
pop bx
pop ax
ret
;============================================================================
;显示提示字符串,参数dh为 行号,列默认为0及返回值 ds:si为字符串首地址
print_string:
push ax
push bx
push cx
push dx
push es
push si
push di
mov ax,0b800h
mov es,ax
mov al,160
mul dh
mov di,ax
mov bx,0
@@ps1: mov al,[si+bx]
cmp al,0
je @@ps2
mov es:[di],al
inc bx
add di,2
loop @@ps1
@@ps2: pop di
pop si
pop es
pop dx
pop cx
pop bx
pop ax
ret
;============================================================================
;显示array序列,并以','分割
;dh行号 无返回值
print_num_with_spilt:
push ax
push bx
push cx
push dx
push si
push di
push sp
push bp
push es
;以下利用栈生成局部变量
mov bp,sp
sub sp,6
mov word ptr [bp-2],0
mov word ptr [bp-4],0
mov word ptr [bp-6],0
;以下确定每行开头的显存地址位置
mov ax,0b800h
mov es,ax
mov al,160
mul dh
mov si,ax
mov cx,10
mov bx,0
;以下确定每个字符的举例(10个数字,每行能显示80个,所以8个字符的距离)
;每个字符两个字节,所以*16
@@pp1: mov al,16
mul bl
mov di,si
add di,ax;
;以下确定数字的正负,并利用/10法拿到每一位
push cx
mov word ptr [bp-2],0
mov ax,[bx+offset array]
test al,80h
jz @@pp5
mov byte ptr es:[di],'-'
add di,2
neg al;拿到绝对值
@@pp5: mov ah,0
mov dl,10
div dl
push ax;商 余数
inc word ptr [bp-2];记录有几位
cmp al,0
je @@pp4 ;结束
jmp short @@pp5
;以下负责把刚刚倒序放入堆栈的每个位数取出,成为正序,并显示
@@pp4: mov cx,[bp-2]
@@pp6: pop ax
add ah,30h;数字变对应的ascii +30h即可
mov es:[di],ah
add di,2
loop @@pp6
;显示完一个数字后显示分隔符','
mov byte ptr es:[di],','
inc bx
pop cx
loop @@pp1
mov sp,bp
pop es;push ax 00 pop ax 00
pop bp
pop sp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
;============================================================================
;显示array序列,由排序函数每次消除一个逆序对时调用,可以对比看出交换了那两个元素 输入
;dh行号 无返回值
print_num:
push ax
push bx
push cx
push dx
push si
push di
push sp
push bp
push es
;以下利用栈生成局部变量
mov bp,sp
sub sp,6
mov word ptr [bp-2],0
mov word ptr [bp-4],0
mov word ptr [bp-6],0
;以下确定每行开头的显存地址位置
mov ax,0b800h
mov es,ax
mov al,160
mul dh
mov si,ax
mov cx,10
mov bx,0
;以下确定每个字符的举例(10个数字,每行能显示80个,所以8个字符的距离)
;每个字符两个字节,所以*16
@@p1: mov al,16
mul bl
mov di,si
add di,ax;
;以下确定数字的正负,并利用/10法拿到每一位
push cx
mov word ptr [bp-2],0
mov ax,[bx+offset array]
test al,80h
jz @@p5
mov byte ptr es:[di],'-'
add di,2
neg al;拿到绝对值
@@p5: mov ah,0
mov dl,10
div dl
push ax;商 余数
inc word ptr [bp-2];记录有几位
cmp al,0
je @@p4 ;结束
jmp short @@p5
;以下负责把刚刚倒序放入堆栈的每个位数取出,成为正序,并显示
@@p4: mov cx,[bp-2]
@@p6: pop ax
add ah,30h;数字变对应的ascii +30h即可
mov es:[di],ah
add di,2
loop @@p6
inc bx
pop cx
loop @@p1
mov sp,bp
pop es;push ax 00 pop ax 00
pop bp
pop sp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
;============================================================================
;选择排序,无参数输入,无返回值
select_sort:
push ax
push bx
push cx
push dx
push si
push di
push sp
push bp
;以下利用栈产生3个局部变量并初始化
mov bp,sp
sub sp,6
mov word ptr [bp-2],0;临时保存每一扫描时的当前最小值
mov word ptr [bp-4],0;每一次扫描时的开始位置(也就是还时无序的序列的起始位置)
mov word ptr [bp-6],0;当前最小值所在位置
;选择排序每次选一个最小的到前面,共需选9次
mov cx,9
mov word ptr [bp-4],0
@@s1: mov byte ptr [bp-2],127;初始化最小
mov ax,[bp-4]
mov [bp-6],ax;初始化最小值所在位置为无序序列开始的位置
push cx
mov cx,10
sub cx,word ptr [bp-4]
mov bx,[bp-4];从无序序列开始的位置开始扫描最小值
@@s2: mov al,[offset array+bx]
cmp al,byte ptr [bp-2]
jge @@s3;如果大于或者等于就跳过,也就是只比最小值还小才执行下面
mov byte ptr [bp-2],al;更新最小值
mov [bp-6],bx;记录下最小值所在位置,方便后面交换
@@s3: inc bx
loop @@s2;扫面一次完成后
mov bx,[bp-4];无序序列最前方
mov ah,[offset array+bx];保存无序序列最前方那个数
mov al,[bp-2]
mov [offset array+bx],al;更新为最小值
mov bx,[bp-6]
mov [offset array+bx],ah;交换
inc word ptr [bp-4]
pop cx
push dx
mov dx,18
sub dx,cx
mov dh,dl
call print_num
pop dx
loop @@s1
mov sp,bp
pop bp
pop sp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
;============================================================================
;快速排序,有两个参数 利用堆栈传入,先push的是待排序列的左边界索引L 后push右边界的索引R
;无返回值
quick_sort:;
push ax
push bx
push cx
push dx
push si
push di
push sp
push bp
;以下利用堆栈创建并初始化局部变量
mov bp,sp;根据入栈顺序推算 [bp+18]是传入的R [bp+20]是传递的L,
sub sp,14
mov word ptr [bp-2],0;pivot主元,取 array[L] array[M] array[R]三者的中位数,其中M=(L+R)/2
mov word ptr [bp-4],0;i 左扫描边界
mov word ptr [bp-6],0;j 右扫描边界
mov word ptr [bp-8],0;当前L-R的长度
mov word ptr [bp-10],0;temp1
mov word ptr [bp-12],0;temp2
mov word ptr [bp-14],0;temp3
;以下检测待排长度,不大于2 不需要快排
mov ax,[bp+18]
sub ax,[bp+20]
inc ax
mov [bp-8],ax
cmp ax,2
jna near ptr @@q1
;以下将三个候选元素放入temp1 temp2 temp3
mov bx,[bp+20]
mov al,[offset array+bx]
mov byte ptr [bp-10],al;储存最左边元素
mov bx,[bp+18]
mov al,[offset array+bx]
mov byte ptr [bp-14],al;储存右边元素
mov ax,[bp+20]
add ax,bx
mov bl,2;
div bl
mov ah,0
mov di,ax;di保存中间的索引
mov al,[offset array+di]
mov byte ptr [bp-12],al;最中间元素
;以下开始对temp1 2 3 排序
cmp al,[bp-14];最右边和中间对比
jle @@q8;如果满足右边大于中间
mov ah,[bp-14]
mov [bp-12],ah
mov [bp-14],al
@@q8: mov al,[bp-12]
cmp al,[bp-10];al指向中间
jge @@q11
mov al,[bp-10];记录长度37,89,-100
cmp al,[bp-14]
jge @@q10
mov ah,[bp-12]
mov [bp-10],ah
mov [bp-12],al
jmp short @@q11
@@q10: mov al,[bp-10]
mov ah,[bp-12] ;al指向左 ah指向中间 dl指向右边 但是现在左》右》中,要交换位置
mov dl,[bp-14]
mov [bp-14],al
mov [bp-12],dl
mov [bp-10],ah
jmp short @@q11
;由于跳转距离太远,用一个中间跳转作为接力
@@q1: jmp near ptr @@q7
;至此temp1《temp2 《temp3排序完成,分别写回array[L] array[M] array[R]
@@q11: mov al,[bp-10]
mov bx,[bp+20]
mov [offset array+bx],al
mov al,[bp-14]
mov bx,[bp+18]
mov [offset array+bx],al
mov al,[bp-12]
mov [offset array+di],al
mov [bp-2],al;储存主元17,5,6
;将array[R-1]和 array[M]交换
mov bx,[bp+18]
dec bx
mov ah,[offset array+bx]
mov [offset array+bx],al
mov [offset array+di],ah;交换r-1和m处的位置
;初始化扫描指针 i,j
mov ax,[bp+20]
inc ax
mov [bp-4],ax;左边界+1
mov ax,[bp+18]
sub ax,2;右边界-2
mov [bp-6],ax
;以下是左扫描
@@q3: mov bx,[bp-4]
mov al,[offset array+bx]
cmp al,[bp-2]
jge @@q2;如果不小于就跳出
inc word ptr [bp-4]
loop @@q3;17,5,6,28
;以下是右扫描
@@q2: mov bx,[bp-6]
mov al,[offset array+bx]
cmp al,[bp-2]
jle @@q4;不大于就跳出
dec word ptr [bp-6]
loop @@q2
;左边第一个大于pivot和右边第一个小于pivot出现了
@@q4: mov ax,[bp-4]
cmp ax,[bp-6]
jnb @@q5;i>=j说明扫描完成了
;i<j 交换即可
mov bx,[bp-4]
mov al,[offset array+bx]
mov si,[bp-6]
mov ah,[offset array+si]
mov [offset array+bx],ah
mov [offset array+si],al;交换一对逆序对
push dx;显示交换后的结果
mov dx,ds:[0ah]
mov dh,dl
call print_num
inc dx
mov ds:[0ah],dx
pop dx
inc word ptr [bp-4]
dec word ptr [bp-6]
loop @@q3
;整个序列扫描完了
@@q5: mov bx,[bp-4]
mov al,[offset array+bx]
mov si,[bp+18]
dec si
mov ah,[offset array+si]
mov [offset array+bx],ah
mov [offset array+si],al
push dx;显示交换后的结果
mov dx,ds:[0ah]
mov dh,dl
call print_num
inc dx
mov ds:[0ah],dx
pop dx
;至此 本序列 左边小于主元的序列+主元+右边大于主元序列生成完毕
;开始递归 z左边的小序列和右边的大序列
mov ax,[bp+20]
push ax
mov ax,[bp-4]
dec ax
push ax
call quick_sort
pop ax
pop ax
mov ax,[bp-4]
inc ax
push ax
mov ax,[bp+18]
push ax
call quick_sort
pop ax
pop ax
jmp short @@q6
;以下是R-L+1 即待排序长度不大于2的情况
@@q7: cmp word ptr [bp-8],1
jna @@q6;如果也不大于1 即直接返回
;即长度为2 比较两个大小排序
mov bx,[bp+20]
mov al,[offset array+bx]
mov si,[bp+18]
mov ah,[offset array+si]
cmp al,ah
jna @@q6
mov [offset array+si],al
mov [offset array+di],ah
jmp short @@q6
@@q6: mov sp,bp
pop bp
pop sp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
;============================================================================
;插入排序
insert_sort:
push ax
push bx
push cx
push dx
push si
push di
push sp
push bp
mov bp,sp
sub sp,6
mov word ptr [bp-2],0
mov word ptr [bp-4],0
mov word ptr [bp-6],0;三个局部变量初始化
mov cx,9
mov bx,1;i
@@i1: mov al,[offset array+bx]
mov ah,0
mov [bp-2],ax;保存array[i]的temp
mov [bp-4],bx;int j=i
@@i3: cmp word ptr [bp-4],0
jna @@i2
mov si,[bp-4]
mov ax,[bp-2]
cmp al,[offset array+si-1]
jg @@i2
mov al,[offset array+si-1]
mov [offset array+si],al
dec word ptr [bp-4]
jmp short @@i3
@@i2: mov al,[bp-2]
mov si,[bp-4]
mov [offset array+si],al
inc bx
push dx
mov dx,18
sub dx,cx
mov dh,dl
call print_num
pop dx
loop @@i1
mov sp,bp
pop bp
pop sp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
;============================================================================
;冒泡排序
buble_sort:
push ax
push bx
push cx
push dx
push si
push di
push sp
push bp
mov cx,9
@@b3: push cx
mov bx,0
@@b1: mov ax,[bx+offset array]
cmp ah,al
jge @@b2 ;jge是有符号数判断 如果大于或等于就跳转
xchg ah,al;如果ah比al小,就要交换了
mov [bx+offset array],ax
@@b2: inc bx
loop @@b1
pop cx
push dx
mov dx,18
sub dx,cx
mov dh,dl
call print_num
pop dx
loop @@b3
pop bp
pop sp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start