汇编语言实现冒泡排序算法

一、 实验要求

  1. 用汇编实现冒泡排序算法。
  2. 在实验三的代码基础上,利用冒泡排序将DEST中数据从小到大重新排序 。
  3. 将冒泡排序算法写成子程序。
  4. 在主程序中,通过设置参数,使用同一个子程序实现从大到小,从小到大排序的自由选择。

二、 实验设计

1. 整体思路

    (a)先将片外(DEST)的数据转到片内

    (b)在片内进行冒泡函数操作,然后重新将值复制到片外

3.流程图

图2-1 ;流程图

3.主要模块设计思路及分析

(1)INSET模块(复制到片内)

        将DEST的值正序复制进来,复制一轮之后,分别递增片内和片外的指针,通过DJNZ操作递减判断(执行NUM次结束),此时片内的值和片外一样,我们就可以在片内进行冒泡函数操作

(2)OUTSET(复制到片外展示结果)

        调用完冒泡函数之后,片内的值就是相应要求的顺序。依次将片内的值复制出去,然后分别递增片内和片外的指针,通过DJNZ操作递减判断(执行NUM次结束),此时片外的值和片内一样,结果就再次展示到片外了

(3)ORDERS

a)通过标志位(7AH)的值判断进行从小到大还是从大到小排列

b)以从小到大举例:

i.初始化排序过程:

  • MOV A, #30H:将常数0x30存储到累加寄存器A中。
  • MOV R1, A:将A中的值加载到寄存器R1中,R1现在包含要排序的数据的地址。
  • MOV A, R2:将寄存器R2中的值加载到A中,通常这是数据集的大小。这个值减1将在后续的比较中使用。
  • DEC A:将A中的值减1,将结果存储在A中,这是后续比较的次数。
  • MOV R5, A:将A中的值加载到寄存器R5中,R5现在包含了剩余比较的次数。
  • CLR 8AH:清除标志位F0,用于标记是否发生了交换。

ii.进入排序循环(LOOP):

  • MOV A, @R1:将R1指向的内存地址的值加载到A中,即加载当前位置的元素值。

iii.比较和交换:

  • MOV R3, A:将A中的值复制到寄存器R3,这是当前轮次的最大值。
  • INC R1:将R1的值加1,将指针指向下一个元素。
  • CLR C:清除进位标志。
  • MOV A, @R1:将R1指向的内存地址的值加载到A中,即加载下一个位置的元素值。
  • SUBB A, R3:用R3的值减去A,结果存储在A中。这一步的目的是比较两个元素的大小,如果A > R3,没有借位,跳转到LOOP1;如果A < R3,发生了借位,需要交换元素。

iiii.借位发生,即需要交换元素:

  • SETB 8AH:设置标志位F0,表示发生了交换。
  • MOV A, R3:将R3的值加载到A中,即将大的值放到A中。
  • XCH A, @R1:交换A和R1指向的内存地址的值,将大的值放到后一个位置。
  • DEC R1:将R1的值减1,将指针回到原来的位置。
  • XCH A, @R1:再次交换A和R1指向的内存地址的值,将小的值放到前一个位置。
  • INC R1:将R1的值加1,指针回到原来的位置。

iiiii.继续循环(LOOP1):

  • MOV A, @R1:将R1指向的内存地址的值加载到A中,即加载当前轮次最大的值。
  • DJNZ R5, LOOP:如果R5不等于0,继续下一轮循环,否则执行下一步。

iiiiii.排序完成或需要重新开始:

  • JB 8AH, SORT:检查标志位F0,如果它被设置,表示发生了交换,需要重新开始排序,跳转到SORT标签。
  • RET:如果没有设置F0,表示排序已完成,返回。

c)从大到小同理

三、实现效果

图3-1 从大到小排列

图3-2 从小到大排列

四、总结

        在进行冒泡操作时,我想直接在片外通过DPTR数据指针操作,但是执行到一些需要指针后移的时候,我发现并没有这样的指针,所以我将数据全部复制到片内之后,通过寄存器指针来进行操做。最后再将结果又复制到外面。

附录代码:

ORG 0000H
	LJMP MAIN
	ORG 2000H
MAIN:
	SRC DATA 30H
	DEST XDATA 2000H
	NUM DATA 20H
	MOV A,#01H				;将累加器里面设置默认值1

	MOV R0,#SRC 			;保存SRC起始地址
	MOV DPTR,#DEST 			;保存DEST起始地址
	MOV R2,#NUM 			;保存字节数量
	MOV R3,#NUM 			;存入片内或者片外RAM都要用,所以保存两次

	ACALL IN
	DEC R0 					;IN子程序中R0最后多加了一次,要减一。即最后一位的地址是49
	ACALL OUT

	MOV DPTR,#DEST			;进行复制片内操作,因为DPYR没有递减操作
	MOV R0,#SRC
	MOV R2,#NUM
	ACALL INSET

	MOV R2,#NUM 			;调用冒泡函数
	SETB 7AH	   			;将7AH标志位置1,从大到小排列
	ACALL ORDERS
	MOV DPTR,#DEST			;进行复制到片外操作,展示出来
	MOV R0,#SRC
	MOV R2,#NUM
	ACALL OUTSET			

	MOV R2,#NUM 
	CLR 7AH		   			;将7AH标志位置0,从小到大排列
	ACALL ORDERS   			;调用冒泡函数
	MOV DPTR,#DEST			;进行复制到片外操作
	MOV R0,#SRC
	MOV R2,#NUM
	ACALL OUTSET			
    SJMP $     
IN: 						;向片内RAM存储
	MOV @R0,A				;将A的值'01H'给到R0地址处
	INC R0					;递增R0地址
	ADD A,#01H				;依次递增A的数据
	DJNZ R2,IN		    	;重复循环,当NUM字节的数被写完了,就不在循环
	RET

OUT: 						;逆序向片外RAM存储
	MOV A,@R0				;将R0地址处的数据给到A
	DEC R0					;依次递减R0
	MOVX @DPTR,A			;把A里面的值给到外部RAM里面,它的起始地址是2000H
	INC DPTR				;依次递增扩展地址
	DJNZ R3,OUT			    ;当所有值复制完了之后,就不在循环
	RET

//把片外的内容给进片内操作
INSET:
	MOVX A,@DPTR			;把2000H的值给A
	MOV @R0, A             ;把片外的值给进来R0
	INC DPTR
	INC R0
	DJNZ R2,INSET
	RET
//把片内的内容给进片外操作
OUTSET:
	MOV A,@R0
	MOVX @DPTR, A
	INC DPTR
	INC R0
	DJNZ R2,OUTSET
	RET

ORDERS: 
	JNB 7AH,SORT   ;标志位为0,执行从小到大的排列
	JB  7AH,SORT2  ;标志位为1,执行从大到小的排列
	RET 	
SORT:
    ; 初始化排序过程
    MOV A, #30H     ;R1里面存放第一个地址
    MOV R1, A       ;R1=30H 
    MOV A, R2       ; A=R2-1,一个数在一个轮回需要比较R2-1次
	DEC A
    MOV R5, A       ; 将A的值给R5
    CLR 8AH         ; 清除标志位F0
    MOV A, @R1      ; 将30H地址处的值给A

LOOP:
    MOV R3, A       ; 初始时将30H地址处的值给R3。后面把当前的最大值给R3
    INC R1          ; R1加一,地址向后移
    CLR C           ; 清除进位标志
    MOV A, @R1      ; A存放后面一个地址的值
    SUBB A, R3      ; A = A - R3
    JNC LOOP1       ; 如果没有借位(即第二数大于第一个数),跳转到LOOP1
	//借位发生了,前面的数大于后面的数,执行以下操作
    SETB 8AH         ; 设置标志位F0,
    MOV A, R3       ; 把R3的值给A(即将大值给A)
    XCH A, @R1      ; 交换A和内存[R1]的值,即把大的值向后移
    DEC R1          ; R1 = R1 - 1,将指针前移
    XCH A, @R1      ; 再次交换A(此时A里面的值被换成小的值了)和内存[R1]的值,将较小的值放到前面
    INC R1          ; R1 = R1 + 1,指针回到原来的位置

LOOP1:
    MOV A, @R1      ; 没有借位时R1地址处的值时最大的,把大的值给A
    DJNZ R5, LOOP   ; 如果R5不等于0,跳转到LOOP
    JB 8AH, SORT     ; 如果标志位F0被设置,跳转到排序函数的重新开始
    RET             ; 返回

SORT2:
    ; 初始化排序过程
    MOV A, #30H     ;R1里面存放第一个地址
    MOV R1, A       ;R1=30H 
    MOV A, R2       ; A=8,一个数在一个轮回需要比较8次
	DEC A
    MOV R5, A       ; 将A的值给R5
    CLR 8AH          ; 清除标志位F0
    MOV A, @R1      ; 将30H地址处的值给A

LOOPA:
    MOV R3, A       ; 初始时将30H地址处的值给R3。后面是把当前较小的值给R3
    INC R1          ; R1加一,地址向后移
    CLR C           ; 清除进位标g志
    MOV A, @R1      ; A存放后面一个地址的值
    SUBB A, R3      ; A = A - R3
    JNC LOOPB       ; 如果没有借位(即第二数大于第一个数),跳转到LOOP1

	//借位发生了,前面的数大于后面的数,执行以下操作
	MOV A, @R1		;重新把R1地址的值给A,因为减法操作把之前的值覆盖了
	DJNZ R5, LOOPA
	JB 8AH, SORT2  
	RET

LOOPB:
	SETB 8AH        ; 设置标志位F0,
	MOV A, @R1		;重新把R1地址的值给A,因为减法操作把之前的值覆盖了
	DEC R1			;R1指针前移
	XCH A,@R1 		;把较大值前移,此时A里面存放较小值
	INC R1			;R1指针加一,回到刚才的位置
	XCH A,@R1		;再次交换,把较小值覆盖当前R1地址处的值,此时A变成了那个较大的值了
	XCH A,R3		;把A与R3交换,即把之前前面的值挪到后面了,A也要存放这个值,以免影响后续操作
    DJNZ R5, LOOPA   ; 如果R5不等于0,跳转到LOOP
    JB 8AH, SORT2     ; 如果标志位F0被设置,跳转到排序函数的重新开始
END

 

  • 26
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 8086汇编语言可以用来实现冒泡排序,具体的步骤如下:1.给定一个数组;2.比较相邻的元素,如果第一个比第二个大,就交换他们两个;3.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;4.针对所有的元素重复以上的步骤,除了最后一个;5.重复步骤1~4,直到排序完成。 ### 回答2: 冒泡排序是一种简单但低效的排序算法,可以用8086汇编语言实现。 8086汇编语言是一种低级别的程序设计语言,因此实现冒泡排序需要一些基本的知识和技巧。下面是一个基于8086汇编语言冒泡排序的示例代码: ``` .model small .stack 100h .data arr db 5, 3, 8, 1, 6 ; 待排序的数组 .code main proc mov ax, @data ; 初始化段寄存器 mov ds, ax mov cx, 5 ; 数组长度 lea si, arr ; 存储数组的偏移地址 outer_loop: mov di, 0 ; 设置内循环起始索引为0 inner_loop: mov al, [si] ; 获取当前元素值 cmp al, [si+1] ; 比较当前元素与下一个元素的大小 jle skip_swap ; 如果当前元素小于或等于下一个元素,则跳过交换 ; 交换两个元素的值 mov ah, [si+1] mov [si+1], al mov [si], ah skip_swap: inc di ; 内循环索引加1 inc si ; 外循环索引加1 cmp di, cx ; 判断内循环是否到达最后一个元素 jb inner_loop ; 如果没有到达最后一个元素,则继续内循环 dec cx ; 外循环计数器减1 cmp cx, 1 ; 判断外循环是否完成 jbe done ; 如果完成,则结束 jmp outer_loop ; 否则,继续外循环 done: mov ah, 4Ch ; 退出程序 int 21h main endp end main ``` 该代码首先定义了一个含有5个元素的数组arr,并将待排序的数赋给它。然后,在主程序中,我们使用了两个循环来实现冒泡排序算法。外循环用于控制排序的轮数,内循环用于比较相邻元素并进行交换。 在内循环中,我们首先比较当前元素与下一个元素的值,如果当前元素大于下一个元素,则交换它们的位置。然后,内循环索引和外循环索引分别加1,循环继续进行。当内循环到达最后一个元素时,我们会将外循环计数器减1,再判断外循环是否已经完成。如果完成,则程序结束;否则,继续外循环。 最后,我们使用汇编语言中的int 21h指令来退出程序。 总的来说,通过使用8086汇编语言实现冒泡排序算法,我们可以通过交换相邻元素的方法来逐步将最大的元素“冒泡”到数组的尾部,从而实现对数组的排序。 ### 回答3: 冒泡排序是一种简单的排序算法,通过多次比较和交换相邻元素的方式将最大的元素逐步 "冒泡" 到数组末尾,直到整个数组排序完成。 对于8086汇编语言实现冒泡排序,我们可以按照以下步骤进行: 1. 首先,需要定义一个存储要排序数据的数组。我们可以使用数据段(DATA)部分来声明一个数组(例如,使用DB指令声明字节类型数组)。 2. 在代码段(CODE)部分,使用LEA指令将数组的基地址加载到BX寄存器中。 3. 定义外层循环,使用CX寄存器来记录待排序元素的个数,并初始化为数组长度减一。外层循环负责控制比较的轮数。 4. 定义内层循环,使用DI寄存器来记录数组索引,并初始化为0。内层循环负责执行相邻元素的比较和交换。 5. 在内层循环中,使用CMP指令比较相邻的两个元素,并根据比较结果使用JG或JL指令实现交换。如果需要交换元素,则可以使用XCHG指令来交换两个元素的值。 6. 在内层循环的末尾,使用INC指令递增DI寄存器的值,以便下一次循环比较下一对元素。 7. 在外层循环的末尾,使用DEC指令递减CX寄存器的值,以便下一次循环减少比较的轮数。 8. 最终,排序完成后,可以使用循环遍历数组,并使用MOV指令将数组元素依次存储到AX或DX寄存器中,以便在程序中进一步使用排序后的数据。 以上就是用8086汇编语言实现冒泡排序的基本步骤和思路。在实际编写程序时,还需要考虑边界条件、数据类型转换以及循环控制等因素。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值