MIPS实现冒泡排序

article/2025/9/18 3:41:33

程序目标

从键盘输入10个无符号字数并从大到小进行排序,排序结果在屏幕上显示出来。

准备工作

  1. 编程的入门级知识:循环、冒泡排序、内存和堆栈的概念
  2. MIPS语法:程序基本结构
  3. 汇编语言:不同寄存器作用、数据存储、系统调用
  4. 编辑器:最低级的记事本就够了,保存为.asm文件即可
  5. PCSpim模拟器:用于运行代码
  6. MIPS指令的参照表:不会表达的语义随手一查

写在前面

汇编代码的可读性比较差,它的操作变量是寄存器,有时候要用到很多,就有点反应不过来。不过,代码读百遍,其义自现,如果这是你的第一个汇编程序,弄懂之后收获还是很大的。

另,如果你知道小火龙的话,hmmm,那么校友你好!网上有很多这样的程序参考啦,但是不要照搬代码呀,完全理解只需要一个下午,加油!

写汇编的时候一小件事都要写一行代码,就会很吝啬去做一些不必要的操作。比如,在以前用C/C++语言写冒泡内存循环的时候总是会在声明j变量同时初始化为0,现在一点也不想这样做了,因为不是什么顺手就能完成的事。我觉得汇编语言程序员一定是短码编程的忠实粉丝。

思路

首先回忆了一下高级语言中冒泡排序的做法,脑海中有个大致的印象

//输入,存到数组
for(int i = 0; i < 10; ++i) // 从大到小排的冒泡
for(int j = i; j < 10; ++j)if(a[j] < a[j + 1]) swap(a[j], a[j + 1]);

第一个问题

汇编语言是如何实现从键盘录入数据的?以及它存在哪?

这个问题比较简单,这涉及一组系统调用命令,形如li $v0, 5(读入一个int),不同的数字编号对应着不同的数据类型,读进来的数就放在$v0中,随用随取。

第二个问题

连续读进来一组数放到哪里?

答案是内存,并用堆栈指针寄存器保存数组的起始地址,之后来一个数就把这个地址往后挪4个字节用sw命令保存到内存,形如sw $v0, 0($t1)。

第三个问题

怎样做循环和比较大小?

汇编语言是没有loop这样的循环语句的,但是有跳转语句和条件判断语句。又可以给每个代码块分区,在该段代码前面加上取的名字和“:”,在跳转的时候就可以用上这个名字来指示跳转位置了。比较大小有一个sltu命令,它可以比较后两个操作数的相等关系,并把比较结果(1/0)存到第一个操作数。

其中关于跳转指令,有三种:j XXX 就是单纯的跳转到XXX的位置;jr和jal则与程序调用函数有关。程序调用函数,当函数调用结束后需要重新继续执行原来的程序,所以在调用函数之前,必须先存储函数返回起始点地址,用于存储这一地址的寄存器在MIPS中是$ra。jal的意思就是跳转到某个地址同时把返回调用点的地址存储在$ra中。而jr用法常见jr $ra,一般是函数调用结束后,用于跳转到返回地址。

第四个问题

有结构有调用函数的程序怎么写?

这里头除了跳转的时候要传参数还有一个比较重要的事情就是开辟栈空间来保存需要使用的局部变量。堆栈向内存地址低的方向增长,所以要用几个参数,一般就*4,让堆栈寄存器保存的指针减掉这个值,形如addi $sp, $sp, -20,意为在栈中开辟5个新地址。

图片说明

现在有了上面那些知识,我们已经可以完成程序的大体了。我的程序的结构:
这里写图片描述
排序的时候时候会发现最好画张图,因为用到的变量比较多,容易忘记寄存器里面装的是什么。
这里写图片描述

运行结果

写好程序之后放到仿真软件里面里面运行,略微改了几个语法错误之后就可以正常跑了。但是输入数据的时候一开始有点懵逼,不知道要在英文输入法下输。下面是正常运行的截图:
这里写图片描述

完整代码

.text
.globl  main
#$gp存数组基址
#$s0存数组大小
#函数调用的时候分别传给a0和a1main:la $a0, str_1            # 输出提示用户输入数组大小li $v0, 4syscallli $v0, 5            # 系统调用把控制台中的数据读入寄存器syscallmove $s0, $v0          # 把数组大小保存到s0la $a0, str_2            # 输出提示用户开始输入数据li $v0, 4syscall#调用read函数move $a0, $gp          # 把$gp作为参数传递给read函数拿到数组基址,不要认为现在gp里面是空move $a1, $s0jal read              # 跳转到read函数的同时保存主函数地址到$ra#打印刚才用户的输入结果li $v0, 4la $a0, str_5syscallmove $a0, $gpmove $a1, $s0jal prinf#调用排序函数move $a0, $gpmove $a1, $s0jal sort#调用输出函数li $v0, 4la $a0, str_3syscallmove $a0, $gpmove $a1, $s0jal prinf#从控制台读数据的read函数
read:addi $sp, $sp, -4      # 栈中开辟1个新地址保存数组元素个数sw $s0, 0($sp)li $s0, 0                # 把s0寄存器置零,作为读数个数的计数器#下面是利用跳转语句和条件控制的读数循环#t0做判断标志位,t1做存储地址read_1:sltu $t0, $s0, $a1     # s0<a1 则t0=1(否则t0=0),即已读入的数的个数小于用户输入的为真beq $t0, $zero, exit_1  # t0=zero 则跳转到exit_1sll $t0, $s0, 2         # s0左移两位add $t1, $a0, $t0      # a0加上t0生成新地址move $t2, $a0li $v0, 5              # 读数syscallsw $v0, 0($t1)            # 保存读入的数据到主存move $a0, $t2addi $s0, $s0, 1        # s0++j read_1exit_1:lw $s0, 0($sp)            # 把栈里面的东西(数组大小)写回寄存器addi $sp, $sp, 4        #弹栈,就是堆栈指针归位jr $ra#排序函数
sort:addi $sp, $sp, -20        # 在栈中开辟5个新地址#依次把要用变量的位置定出来并压栈sw $ra, 16($sp)          # 返回地址sw $s3, 12($sp)          # 数组大小sw $s2, 8($sp)          # 数组基址sw $s1, 4($sp)          # jsw $s0, 0($sp)          # imove $s2, $a0move $s3, $a1move $s0, $zeroforOut:slt $t0, $s0, $s3      # 如果i<n,则t0=1beq $t0, $zero, exit1   # 如果t0=0,跳转到exit1退出外层循环addi $s1, $s0, -1       # j = i - 1forIn:slti $t0, $s1, 0        # 如果s1<0,则t0=1bne $t0, $zero, exit2   # 如果t0!=0,跳转到exit2sll $t1, $s1, 2         # $tl = j*4add $t2, $s2, $t1		# $t2存了arr[j]的地址lw $t3, 0($t2)            # 取出arr[j]的数据到$t3lw $t4, 4($t2)            # 取出arr[j+1]的数据到$t4slt $t0, $t3, $t4      # 如果arr[j]<arr[j+1], 则t0=1beq $t0, $zero, exit2   # 不满足上面条件,跳转到exit2退出内层循环move $a0, $s2           # 把数组地址这个参数传给swap函数move $a1, $s1           # 另一个参数j也传过去jal swapaddi $s1, $s1, -1       # j--j forInexit2:addi $s0, $s0, 1        # i++j forOut                # 跳至外层循环exit1:lw $s0, 0($sp)lw $s1, 4($sp)lw $s2, 8($sp)lw $s3, 12($sp) lw $ra, 16($sp)addi $sp, $sp, 20jr $raswap:sll $t0, $a1, 2     # j左移两位放到t0中add $t0, $a0, $t0  # 基址值加上偏移量arr[j]的地址lw $t1, 0($t0)        # 把arr[j]的值放入t1中lw $t2, 4($t0)        # 把arr[j+1]的值放入t2中sw $t1, 4($t0)        # arr[j]=arr[j+1]sw $t2, 0($t0)        # arr[j+1]=arr[j]jr $ra             # 返回调用前的地址处#输出函数prinf部分,功能是打印一个数组的所有元素,实现和读入差不多
prinf:addi $sp, $sp, -4sw $s0, 0($sp)      #保存寄存器s0 s1li $s0, 0                #将s0置零prinf_1:sltu $t0, $s0, $a1beq $t0, $zero, exit_2sll $t0, $s0, 2add $t1, $a0, $t0move $t2, $a0lw $a0, 0($t1)li $v0, 1syscallli $a0, ','li $v0, 11syscall move $a0, $t2addi $s0, $s0, 1j prinf_1exit_2:lw $s0, 0($sp)addi $sp, $sp, 4jr $ra.data
str_1:.asciiz "请输入要排序的数组的大小:\n"
str_2:.asciiz "请输入要排序的数:\n"
str_3:.asciiz "\n排序的结果为:\n"
str_5:.asciiz "输入的数为:\n"

http://chatgpt.dhexx.cn/article/1gYvfaP8.shtml

相关文章

c语言数组实现冒泡排序

数组实现冒泡排序 什么是冒泡拍排序用数组实现总结 什么是冒泡拍排序 首先&#xff0c;需要了解一下什么是冒泡排序&#xff0c;定义&#xff1a;冒泡排序&#xff08;Bubble Sort&#xff09;也是一种简单直观的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个…

汇编实现排序——冒泡排序

冒泡排序算法的运作如下&#xff1a;&#xff08;从后往前&#xff09; 1.比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。 2.对每一对相邻元素作同样的工作&#xff0c;从开始第一对到结尾的最后一对。在这一点&#xff0c;最后的元素应该会是最大的数。…

冒泡排序与qsort排序

先来比较两者的优缺点&#xff1a; 冒泡排序qsort排序优简单&#xff0c;稳定效率高&#xff0c;适用性广劣适用性差&#xff0c;速度慢较为复杂 一、冒泡排序&#xff1a; 底层思路&#xff1a; 如此循环9轮得到 知道了思路就可以写代码了 #include<stdio.h> void bubbl…

易语言冒泡排序

冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换&#xff0c;也就是说该数列已经排序完成。这个算…

实现冒泡排序函数

#1 冒泡排序思想 假设我们现在又是个乱序的数字&#xff0c;10 2 3 4 1 6 8 5 9 7&#xff0c;要对这十个数字进行升序排序&#xff08;越往右数字越大&#xff09;&#xff0c;我们可以这样子做&#xff1a; 取出最左边的数字&#xff08;10&#xff09;&#xff0c;然后依次…

用汇编实现冒泡排序

对应的C语言代码如下&#xff1a; int number[6]{12,3,2,5,6,7}; for(int i0;i<6;i) {for(int j0;j<6;j) {if(a[i]<a[j]) {int tempa[i];a[i]a[j];a[j]temp;}} } 汇编代码&#xff08;从大到小排列&#xff09;&#xff1a; DATA SEGMENTBUF DB 12,3,2,5,6,7 …

c语言冒泡排序while循环,冒泡排序算法,C语言冒泡排序算法详解

冒泡排序是最简单的排序方法&#xff0c;理解起来容易。虽然它的计算步骤比较多&#xff0c;不是最快的&#xff0c;但它是最基本的&#xff0c;初学者一定要掌握。 冒泡排序的原理是&#xff1a;从左到右&#xff0c;相邻元素进行比较。每次比较一轮&#xff0c;就会找到序列中…

冒泡排序与qsort函数详解

提及到排序&#xff0c;冒泡排序算是一个很基础的排序了。那么冒泡排序到底是什么呢&#xff1f;冒泡排序在什么情况下使用呢&#xff1f;qsort函数又是什么呢&#xff1f;接下来我给大家通过举例来详细解释一下。 引入 这里给大家一个题目&#xff0c;大家可以简单思考一下&am…

模仿qsort功能实现一个冒泡排序

目录 1.简单介绍qsort 2.模仿qsort实现冒泡排序 qsort函数原型 void qsort (void* base, size_t num, size_t size,int (*compar)(const void*,const void*)); 一些解释: 1.base:指向要排序数组的第一个对象 类型为void* 2.num:base所指向数组的元素总数…

字符串的冒泡排序

字符串的冒泡排序 本题要求使用冒泡排序法对任意给定的N个字符串按从小到大排序&#xff0c;输出扫描完第K&#xff08;K<N&#xff09;遍后的中间结果序列。 输入格式&#xff1a; 输入在第1行中给出N和K&#xff08;1≤K<N≤100&#xff09;&#xff0c;此后N行&…

冒泡排序(C语言)

文章目录 1. 冒泡排序如何实现1.1 冒泡排序函数的错误设计1.2 数组名是什么&#xff1f;1.3 冒泡排序函数的正确设计 1. 冒泡排序如何实现 往往我们在写代码的时候&#xff0c;会将数组作为参数传个函数&#xff0c;比如&#xff1a;我要实现一个冒泡排序&#xff08;这里要讲算…

模仿qsort实现一个冒泡排序的通用算法

&#x1f4a5;qsort函数介绍&#x1f4a5;冒泡排序介绍&#x1f4a5;什么是冒泡排序的通用算法&#x1f4a5;模仿qsort的一个冒泡排序的通用算法&#x1f4a5;结语 &#x1f525;qsort函数介绍 在一些编程题中经常需要你按照某个指标按照从小到大或从大到小输出一些数据&#x…

c语言冒泡排序数组指针,c语言冒泡排序,指针,数组

冒泡排序算法的运作如下: 比较相邻的元素。如果第一个比第二个大,就交换他们两个。 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 针对所有的元素重复以上的步骤,除了最后一个。 持续每次对越来越少的元素重复上面…

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

题目描述&代码 有一个首地址为A的N字数组&#xff0c;编写程序采用冒泡排序使该数组中的数按照从大到小的次序整序。 数据存储在A的数组中&#xff08;即内存中&#xff09;&#xff0c;我们需要利用冒泡排序实现从大到小排序。 ;description data SEGMENT USE16a dw …

实现一个通用的冒泡排序 - C语言

一、前言 在对一组数组进行排序是&#xff0c;我们经常用到冒泡排序&#xff0c;它是一种较简单的排序算法。 冒泡排序的原理如下&#xff1a; 比较相邻的两个元素。如果第一个比第二个大&#xff0c;就交换它们两个。对每一对相邻元素做同样的工作&#xff0c;从开始第一对到…

第三次项目需求文档

北京理工大学大学疫苗接种系统 文章目录 一.UML图1.用例图2.类图3.活动图4.顺序图 二.需求规格说明文档1.需求和功能说明1.1.获取的功能需求.2.功能划分1.2.1.登录界面1.2.2.预约服务1.2.3.接种查询 2.工作量展示2.1.需求获取2.1.1.项目前景和范围2.1.2.涉众分析2.1.4.面谈 2.…

项目文档编写规范

此文件是 项目文档编写规范 的 readme 编写范例&#xff0c;点击 我要改进 即可查看其 Markdown 内容。 项目概述 产品名称&#xff1a;LaraBBS 项目代号&#xff1a;larabbs 官方地址&#xff1a; https://learnku.com/laravel/t/6592 LaraBBS 是一个简洁的论坛应用…

项目文档管理

项目文档管理&#xff08;Project Documents Management&#xff09; 目录 [隐藏 ] 1 项目文档管理的概述 2 文档管理在项目进程中的重要作用 3 如何建立项目文档管理规定 4 参考文献 <script type"text/javascript"> if (window.showTocToggle) { var …

项目文档如何管理?

在项目进行过程中&#xff0c;会产生很多相关文档文件。通常会散落的分布在不同员工的设备中以及聊天记录中&#xff0c;这种管理方式不仅增大了文件丢失的风险&#xff0c;而且不利于团队文件协作&#xff0c;以及项目经验知识沉淀。 项目文件的管理是项目管理中不可缺少的一…

项目部署文档

1.前提环境 名称版本jdkjdk1.7(建议不要超过1.8)mysql5.7tomcat7(建议不要超过8) 输入 java -version出现如下为jdk安装成功 2.Java环境安装与配置 参见&#xff1a;https://www.linuxidc.com/Linux/2017-01/139212.htm 3.Tomcat安装部署说明 以使用提供的tomcat为例tar z…