汇编——实现冒泡排序+讲解

本文详细讲解如何使用汇编语言实现冒泡排序,通过数据准备和双重循环来优化排序过程,减少比较次数。文章介绍了如何利用地址计数器计算元素个数,并在内外层循环中有效地进行数值比较和交换,最终通过debug查看内存验证排序结果。

题目描述&代码

有一个首地址为A的N字数组,编写程序采用冒泡排序使该数组中的数按照从大到小的次序整序。

数据存储在A的数组中(即内存中),我们需要利用冒泡排序实现从大到小排序。

;description
data SEGMENT USE16
	a    dw  8,16,41,22,50
	n    equ ($-a)/2
data ENDS
;description
stack SEGMENT USE16
	      dw 32 dup(?)
stack ENDS
;description
code SEGMENT USE16
	      ASSUME CS:CODE, DS:DATA, SS:STACK
	start:
	      mov    ax,data
	      mov    ds,ax
	;存储n-1到cx
	      mov    cx,n
	      dec    cx
	loop2:
	;存储cx到dx
	      mov    dx,cx
	      shl    dx,1
	      mov    si,0
	loop1:
	      mov    ax,a[si]
	      CMP    word ptr ax,a[si+2]
	      ja     next
	;bx相当于是中间变量,交换
	      mov    bx,ax
	      mov    ax,a[si+2]
	      mov    a[si+2],bx
	      mov    a[si],ax
	next: 
	      add    si,2
	      cmp    si,dx
	      jnz    loop1

	      loop   loop2

	      mov    ah,4ch
	      int    21h
code ENDS
end start

冒泡排序

对于一个数组,我们的冒泡排序是这样的:
比较相邻两项,将小的放在后面,重复n-1次,就能得到有序序列

这是一趟:
在这里插入图片描述
很明显,我们这样就能将最小的元素排在我们想要的位置。
然后进行第二轮,同理我们可以将第二小的元素排在合适的位置。

然后是第三轮、第四轮……,直到第n-1轮整体有序。
每一次最小的元素被选出来,就像是交换到了水面上,所以叫做冒泡排序。

这里再做一个优化,我们可以看出来,每一次需要排序的元素个数都会少一个。
实现部分我是用cx寄存器存储循环的n-1次,每一轮减一,刚好和需要排序的个数相同。

实现

数据准备

首先,我们已知数据存储在a数组中,这里我们计算元素个数的方式是采用了地址计数器"$",他的作用是保存当前正在汇编的指令的偏移地址
还有伪指令equ,有一点像等号,其实就是一个赋值操作,不过只能做一次。
在赋值的时候,地址计数器刚好将数组存入内存,并且地址计数器保存的是指令的第一个字节位置
图示:(这里的数据为十六进制)
在这里插入图片描述
这样我们用地址计数器减去a(这里是一个地址)就能得到该数组包含的字节个数,然后除以2就是字的个数了。

双重循环

这里的循环很明显是两层,如果都是loop指令就需要进行将cx寄存器压栈,我们采用的是cx和dx分别作为外层和内层的计数器。

在外层循环中,我们需要将cx的值递减(loop指令完成),同时需要给dx寄存器赋值,原因在上面说过了,我们想要优化一下排序次数。
因为数组的数据类型为dw,所以si下标一次加2,我们需要将dx乘二(左移一位)从而和si比较

在内层循环中,需要比较a[si]和a[si+2],但是因为两个不能都是内存寻址,这里我们先将a[si]放在ax中,然后和a[si+2]比较,注意在换的过程中是需要中间变量的,而且是修改数组的值。(我个憨憨最开始就只修改了ax寄存器的值)
在每一次交换之后,将si寄存器内容加2,和dx的值比较一下,如果不同说明没有达到最后,否则停止进入外层循环。
这里声明一下,内存中的数据都是以字节为单位进行操作的,所以我们将si加2(dw类型)

因为懒得写输出结果,所以我就直接debug查看内存了:
在这里插入图片描述
先使用g运行程序,然后找到存储data段的地址,因为我们的数组a是最开始的,所以偏移地址为0000。

因为地址从左到右是从低到高,所以3200表示的其实是0032,也就是十进制的50,以此类推。

对debug感兴趣的可以看这篇博客

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值