本文仅讨论如何用汇编语言实现一个简单的快速排序算法,不探讨快速排序算法的原理;若读者对于快速排序算法还不熟悉,请自行阅读其它文章。
一、相关软件
MARS(MIPS Assembler and Runtime Simulator),下载连接:
计算机组成原理全套实验软件(包含电路仿真器)网盘下载https://pan.baidu.com/s/1YfnpPLGUR7H8OmYJloujjQ
提取码: mips
安装注意:MIPS为JAVA可执行文件(Executable Jar File),需要先安装JAVA环境(包含在其中)
二、根据C语言编写汇编代码
本部分主要通过对应的C语言代码来编写对应的MIPS汇编语言代码,适用于汇编语言的初学者,对于熟练者可以直接编写。
完整代码在第三部分
快速排序算法的C语言代码如下:
#include <stdio.h>
void quick_sort(int *arr, int start, int end);
int main() {
int arr[] = {9, 8, 7, 6, 4, 5, 3, 2};
int len = sizeof(arr) / sizeof(arr[0]);
quick_sort(arr, 0, len - 1);
printf("The Result is:\n");
for (int i = 0; i < len; i++) {
printf("%d", arr[i]);
printf(" ");
}
return 0;
}
void quick_sort(int *arr, int start, int end) {
if (end <= start) return;
//取第一个元素为支点
int pivot = arr[start];
int left = start + 1;
int right = end;
while (left <= right) {
if (arr[left] <= pivot) {
left++;
} else if (arr[right] >= pivot) {
right--;
} else {
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int tmp = arr[right];
arr[right] = arr[start];
arr[start] = tmp;
quick_sort(arr, start, right - 1);
quick_sort(arr, right + 1, end);
}
(1)数据声明
.data
Array:
.align 2
.word 9,8,7,6,4,5,3,2
Space:
.asciiz " "
Str:
.align 0
.ascii "The Result is:\n"
Array数组保存要排序的数组和排序之后的数组,以字(32比特)对齐,因此在之后的读写该数组时,需要将字地址乘以4得到字节地址的偏移量!!!
(2)编写主函数
.globl main
main:
li $a0,0
li $a1,28
jal quick_sort
li $t0,0
li $t1,32
la $a0,Str
jal print_str
L:
lw $a0,Array($t0)
addi $t0,$t0,4
jal print_int
la $a0,Space
jal print_str
bne $t0,$t1,L
li $v0,17
li $a0,0
syscall
主函数主要的功能为调用快速排序函数和输出运行结果,数组一共有8个字,因此其字节地址的偏移范围为0-28,放在参数寄存器$a0和$a1里面,对应C语言中的start和end
(3)快速排序函数(递归)
quick_sort:
slt $t3,$a1,$a0
bne $t3,$zero,Exit
addi $sp,$sp,-16
sw $a0,-12($sp)
sw $a1,-8($sp)
sw $ra,-4($sp)
addi $t0,$a0,0
addi $t1,$a1,0
lw $t2,Array($t0) #支点
li $s2,-1
sw $s2,Array($t0)
Loop:
slt $t3,$t0,$t1
beq $t3,$zero,End
lw $s0,Array($t0)
lw $s1,Array($t1)
bne $s0,$s2,Else
slt $t3,$s1,$t2
beq $t3,$zero,E1
sw $s0,Array($t1)
sw $s1,Array($t0)
j Loop
E1:
addi $t1,$t1,-4
j Loop
Else:
slt $t3,$t2,$s0
beq $t3,$zero,E2
sw $s0,Array($t1)
sw $s1,Array($t0)
j Loop
E2:
addi $t0,$t0,4
j Loop
End:
sw $t2,Array($t0)
sw $t0,0($sp)
lw $a0,-12($sp)
lw $a1,-8($sp)
addi $a1,$t0,-4
jal quick_sort
lw $a0,-12($sp)
lw $a1,-8($sp)
lw $t0,0($sp)
addi $a0,$t0,4
jal quick_sort
lw $a0,-12($sp)
lw $a1,-8($sp)
lw $ra,-4($sp)
addi $sp,$sp,16
Exit:
jr $ra
下面详解该函数的基本过程:
1.首先判断 $a1
(end)是否小于 $a0(end)
,如果是,该过程为叶过程,直接返回;否则为非叶过程,为函数开辟栈空间,保存两个参数寄存器的内容和$ra中的返回地址;
2.将 $t0
和 $t1
分别赋值为 $a0
和 $a1
,并将数组中的第一个元素作为支点存放在 $t2
中,原数组的位置置为-1
3.进入循环,首先判断当前数组下标是否已经超过结束位置,如果是退出循环,直接跳转到 End
标签;否则取出当前下标对应的数组元素放入 $s0(称为当前位置元素)
和结束位置对应的数组元素放入 $s1(称为结束位置元素)
4.
判断当前元素($s0)是否等于支点元素($t2):
如果是,则比较结束位置元素和支点元素的大小,如果结束位置元素小于支点元素,则将结束位置元素存放在当前位置,将当前元素存放在结束位置,然后跳转到循环开始处;如果结束位置元素大于或等于支点元素,则将结束位置下标减 4(数组下标向前移动一位),继续循环
反之,则比较当前元素和支点元素的大小。如果当前元素大于或等于支点元素,则比较结束位置元素和支点元素的大小,如果结束位置元素小于支点元素,则将结束位置元素存放在当前位置,将当前元素存放在结束位置,然后跳转到循环开始处。如果结束位置元素大于或等于支点元素,则将当前下标加 4(数组下标向后移动一位),继续循环
5.最后$t0的数值即为支点的位置,将这个值保存入栈,递归调用快速排序函数对支点元素左边的子数组和右边的子数组进行排序
6.销毁栈帧,退出函数
三、完整的汇编代码
.data
Array:
.align 2
.word 9,8,7,6,4,5,3,2
Space:
.asciiz " "
Str:
.align 0
.ascii "The Result is:\n"
.text
.globl main
main:
li $a0,0
li $a1,28
jal quick_sort
li $t0,0
li $t1,32
la $a0,Str
jal print_str
L:
lw $a0,Array($t0)
addi $t0,$t0,4
jal print_int
la $a0,Space
jal print_str
bne $t0,$t1,L
li $v0,17
li $a0,0
syscall
quick_sort:
slt $t3,$a1,$a0
bne $t3,$zero,Exit
addi $sp,$sp,-16
sw $a0,-12($sp)
sw $a1,-8($sp)
sw $ra,-4($sp)
addi $t0,$a0,0
addi $t1,$a1,0
lw $t2,Array($t0) #支点
li $s2,-1
sw $s2,Array($t0)
Loop:
slt $t3,$t0,$t1
beq $t3,$zero,End
lw $s0,Array($t0)
lw $s1,Array($t1)
bne $s0,$s2,Else
slt $t3,$s1,$t2
beq $t3,$zero,E1
sw $s0,Array($t1)
sw $s1,Array($t0)
j Loop
E1:
addi $t1,$t1,-4
j Loop
Else:
slt $t3,$t2,$s0
beq $t3,$zero,E2
sw $s0,Array($t1)
sw $s1,Array($t0)
j Loop
E2:
addi $t0,$t0,4
j Loop
End:
sw $t2,Array($t0)
sw $t0,0($sp)
lw $a0,-12($sp)
lw $a1,-8($sp)
addi $a1,$t0,-4
jal quick_sort
lw $a0,-12($sp)
lw $a1,-8($sp)
lw $t0,0($sp)
addi $a0,$t0,4
jal quick_sort
lw $a0,-12($sp)
lw $a1,-8($sp)
lw $ra,-4($sp)
addi $sp,$sp,16
Exit:
jr $ra
print_int:
addi $v0,$zero,1
syscall
jr $ra
print_str:
addi $v0,$zero,4
syscall
jr $ra
四、运行结果