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

一、 实验要求

  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
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值