8086汇编冒泡排序子程序设计程序

一、题目需求分析

1 任务说明

(1)程序背景

① 数据段首字节存放学生人数20,其后连续20个字节为汇编课程成绩数据。

② 需自主编写sort冒泡排序子程序,对现有成绩数组进行升序排序,排序结果直接覆盖存储在原数据内存区域。

(2)子程序规范

① 入口参数:DS:BX为待排序成绩数组首地址,CX为待排序数据总个数。

② 出口参数:无,采用原地排序方式,直接修改原数组数据。

③ 排序算法:采用标准冒泡排序算法,实现成绩从小到大升序排列。

(3)主程序预置逻辑

① 读取数据段偏移地址0处的数据,获取学生总人数并送入CX寄存器。

② 对BX寄存器赋值为1,指向第一个有效成绩的存储地址。

③ 调用自定义sort排序子程序完成数组排序,执行完成后正常退出程序。

2 冒泡排序原理

(1)外层循环控制排序轮次

① 包含n个元素的数组,最多需要执行n-1轮冒泡排序。

② 每一轮排序都会将当前未排序区域内的最大值,通过相邻比较交换冒泡到末尾,完成末尾元素有序。

(2)内层循环完成相邻元素比较交换

① 从数组起始位置开始,依次两两比较相邻字节数据。

② 若前一个数据大于后一个数据,立即交换两个内存单元的值,实现升序排序规则。

(3)就地存储

① 程序不额外开辟内存空间,所有比较、交换操作均在原数据段完成,直接覆盖原始数据。

二、完整汇编程序

assume cs:cseg,ds:dseg,ss:sseg

sseg segment stack

dw 100H dup (?)

sseg ends

dseg segment

db 20 ;数据个数

db 98,61,57,82,89,73,61,58,53,54

db 84,78,70,64,84,63,76,84,83,86

dseg ends

cseg segment

start:

mov ax, dseg

mov ds, ax

mov cl, ds:[0]

mov ch, 0 ;cx = 数据总数20

mov bx, 1 ;成绩起始偏移地址

call sort

mov ax, 4c00h

int 21h

;子程序名:sort

;功能:对从DS:(BX)开始的(cx)个字节升序冒泡排序

;入口:DS:BX=数组首地址,CX=元素个数

;出口:数组就地排序,无返回参数

sort:

(1)保护现场

① 保存用到的寄存器BP、SI、DI、AX、DX,避免破坏主程序数据。

push bp

push si

push di

push ax

push dx

(2)设置外层循环计数器

① 元素个数送入BP,外层循环执行次数为数据个数减一。

mov bp, cx

dec bp ;外层循环次数n-1

outer:

(3)内层循环初始化

① SI为数组遍历指针,每一轮冒泡从头开始比较元素。

mov si, bx

mov di, cx ;内层循环次数随轮次递减

dec di

inner:

(4)取出相邻两个数进行比较

mov al, [si]

mov dl, [si+1]

cmp al, dl

jbe no_swap ;前数≤后数,无需交换

(5)前数更大,交换两个单元的值

mov [si], dl

mov [si+1], al

no_swap:

inc si ;指针后移,比较下一对元素

dec di

jnz inner ;内层循环未结束则继续比较

dec bp

jnz outer ;外层循环未结束则开启下一轮冒泡

(6)恢复所有寄存器现场

pop dx

pop ax

pop di

pop si

pop bp

ret

cseg ends

end start

三、核心代码逻辑说明

1 现场保护机制

(1)寄存器占用说明

① 子程序运行过程中会修改BP、SI、DI、AX、DX寄存器数值,为避免覆盖主程序原始数据,进入子程序后统一压栈保存。

② 子程序执行完毕后,按先进后出原则对应出栈恢复寄存器数据,保证主程序运行不受影响。

2 双重循环结构

(1)外层循环功能

① 外层循环控制整体冒泡轮次,n个元素最多执行n-1轮,保证全部元素有序。

(2)内层循环功能

① 内层循环负责相邻元素两两对比交换,每一轮外层循环结束,当前最大值自动排序至未排序区域末尾。

② 每完成一轮冒泡,有序元素数量增加,内层循环比较次数逐轮递减,减少无效运算。

3 内存交换操作

(1)数据交换方式

① 借助AL、DL通用寄存器暂存相邻两个内存单元的成绩数据,避免数据覆盖丢失。

② 直接通过MOV指令修改原数据段内存单元数值,实现原地交换,无需额外占用内存空间。

4 寻址方式

(1)内存寻址规则

① BX寄存器固定作为成绩数组的基地址,定位数组起始位置。

② SI寄存器作为动态偏移指针,实现逐字节遍历数组,采用寄存器间接寻址方式读取和修改内存数据。

四、程序调试验证方案

1 调试工具:DEBUG

(1)断点调试操作

① 将编译链接生成的EXE程序载入DEBUG工具,在调用sort子程序的位置设置断点。

② 单步进入子程序,跟踪SI指针偏移过程,实时观察相邻内存单元的数据变化与交换过程。

③ 子程序执行完毕后,查看数据段DS:01起始的连续20个字节数据,验证排序结果。

2 人工核对

(1)原始成绩数据

① 98,61,57,82,89,73,61,58,53,54,84,78,70,64,84,63,76,84,83,86

(2)程序运行后升序结果

① 53,54,57,58,61,61,63,64,70,73,76,78,82,83,84,84,84,86,89,98

(3)验证结论

① 程序排序结果与人工升序排序结果完全一致,排序功能准确无误。

五、程序优缺点总结

1 优点

(1)编程规范严谨

① 严格遵循8086汇编子程序编写规范,入口出口参数明确,寄存器现场完整保护,模块化程度高。

(2)内存利用率高

① 采用原地冒泡排序算法,不额外开辟数据存储空间,仅通过寄存器中转数据,内存占用极小。

(3)逻辑清晰易懂

① 双层循环结构贴合经典冒泡排序原理,代码分层清晰,注释完整,便于理解、调试与修改。

(4)贴合题目要求

① 排序结果直接覆盖原数据区,完全满足题目就地存储的设计要求。

2 可优化方向

(1)优化无效循环

① 可增设排序标志位,若某一轮冒泡中未发生任何数据交换,证明数组已完全有序,可提前终止循环,提升运行效率。

(2)拓展排序规则

① 可通过修改条件跳转指令,将升序排序改为降序排序,仅需将jbe指令替换为ja指令即可,适配更多排序场景。