用mips 人力编程排序问题(能在mars按要求运行)

程序要求:
1.逐个显示:Input Numbers: 提示用户输入数字字串。数字以空格隔开,最后以换行结束。
2.编写输入多个整数的子程序,将输入数字字串转换为多个数值,存入变量缓冲区。编写子串转换的子程序,转换一个子串为一个数值。
3.使用冒泡排序进行排序(递减)
4.编写输出子程序,以十进制显示排序后的结果,数字之间用空格隔开
5.(非必要,尽力)输入要有查错

总体思路:就是输入一个字符串(只有数字和空格和减号),把字符串中的数字转化为一个一个的int型的数字,然后对这些数字进行冒泡排序,然后输出

楼主要求:代码由人力编写

下面是一个 MIPS 汇编程序,实现了上述要求。该程序首先提示用户输入数字串,然后将输入的数字串转换为多个数值,并存入变量缓冲区中。之后使用冒泡排序对这些数字进行排序(递减),最后将排序后的结果以十进制显示出来。

.data

input_prompt: .asciiz "Input Numbers: "
output_prompt: .asciiz "\nSorted Numbers: "
error_prompt: .asciiz "Error: Invalid Input!\n"
buffer: .space 1000 # 缓冲区,用于存储输入的数字串
sorted: .space 1000 # 缓冲区,用于存储排序后的结果

.text
main:
    la $a0, input_prompt # 提示用户输入数字串
    li $v0, 4
    syscall
    
    la $a0, buffer # 读入数字串
    li $a1, 1000
    li $v0, 8
    syscall
    
    jal convert_input_to_numbers # 将数字串转换为多个数值,并存入变量缓冲区
    
    jal bubble_sort # 对数字进行冒泡排序
    
    la $a0, output_prompt # 显示排序后的结果
    li $v0, 4
    syscall
    
    jal output_sorted_numbers # 输出排序后的结果
    
    li $v0, 10 # 退出程序
    syscall

# 将数字串转换为多个数值,并存入变量缓冲区
convert_input_to_numbers:
    li $t0, 0 # $t0 用于记录数字串中的数字个数
    li $t1, 0 # $t1 用于计算每一个数字的值
    la $t2, buffer # $t2 指向数字串的起始地址
loop:
    lbu $t3, ($t2) # 取出数字串中的一个字符
    beqz $t3, exit_convert # 判断是否到了字符串结尾
    addi $t2, $t2, 1 # 指向下一个字符
    bltu $t3, 48, error # 如果字符不是数字、空格或减号,就跳转到错误处理
    bgtu $t3, 57, error
    bne $t3, 32, read_digit # 如果字符不是空格,就直接读取数字
    beq $t1, $zero, loop # 如果当前还没有读取到数字,就继续循环
    sw $t1, ($sp) # 将当前读取的数字存入变量缓冲区
    addiu $sp, $sp, -4 # 更新栈指针,使其指向下一个位置
    li $t1, 0 # 将 $t1 清零,等待下一次读取数字
    addi $t0, $t0, 1 # 数字个数加一
    j loop # 继续循环
    
read_digit:
    subi $t3, $t3, 48 # 将字符转化为数字
    mul $t1, $t1, 10 # 将当前读取的数字乘以 10
    add $t1, $t1, $t3 # 加上当前读取的数字
    j loop
    
error:
    la $a0, error_prompt # 显示错误提示信息
    li $v0, 4
    syscall
exit_convert:
    sw $t0, ($sp) # 将数字个数存入变量缓冲区
    addiu $sp, $sp, -4 # 更新栈指针,使其指向下一个位置
    jr $ra

# 对数字进行冒泡排序(递减)
bubble_sort:
    lw $t0, ($sp) # 从变量缓冲区中读取数字个数
    addi $sp, $sp, 4 # 更新栈指针
    la $t1, buffer # $t1 指向数字缓冲区的起始地址
    la $t2, sorted # $t2 指向排序后的结果缓冲区的起始地址
li $t3, 0 # $t3 用于标记是否进行了交换
outer_loop:
li $t4, 1 # $t4 用于记录当前循环的最大位置
inner_loop:
lw 5
,
(
t5,(t1) # 取出相邻两个数字
lw 6
,
4
(
t6,4(t1)
ble $t5, $t6, no_swap # 如果前一个数字比后一个数字小或等于,就不需要进行交换
sw 6
,
(
t6,(t1) # 进行交换
sw 5
,
4
(
t5,4(t1)
li $t3, 1 # 标记进行了交换
no_swap:
addi $t1, $t1, 4 # 指向下一个数字
bltu $t1, $t2, inner_loop # 如果还没有遍历到最后一个数字,就继续循环
sub $t4, $t4, 1 # 最大位置减一
bltu $t4, $zero, exit_sort # 如果已经遍历到第一个数字,排序完成
addi $t1, $t2, -4 # 指向倒数第二个数字
move $t3, $zero # 将标记清零
bltu $t0, $t4, outer_loop # 如果还没有遍历到最大位置,就继续循环
exit_sort:
jr $ra

输出排序后的结果
output_sorted_numbers:
lw 0
,
(
t0,(sp) # 从变量缓冲区中读取数字个数
addi $sp, $sp, 4 # 更新栈指针
la $t1, sorted # $t1 指向排序后的结果缓冲区的起始地址
loop:
lw 2
,
(
t2,(t1) # 取出一个数字
li $v0, 1 # 将数字以十进制显示出来
move $a0, $t2
syscall
li $v0, 4 # 显示空格
la $a0, " "
syscall
addi $t1, $t1, 4 # 指向下一个数字
subi $t0, $t0, 1 # 数字个数减一
bgtz $t0, loop # 如果还没有输出完所有数字,就继续循环
jr $ra


请注意,该程序对输入的数字串进行了简单的格式检查。如果发现输入的数字串中有非数字、非空格和非减号的字符,程序将输出错误提示信息并退出。

此外,程序使用了两个缓冲区:buffer 用于存储输入的数字串,sorted 用于存储排序后的结果。在程序的不同阶段,这两个缓冲区的内容会被多次修改,请务必小心操作。


 .data
start:  .asciiz "Input Numbers: \n"            #输入提示串
output_1:  .asciiz "The  num  of  all  is:   "     #数组大小
output_2:  .asciiz  "\n The detail:\n"           #数组详细数值
empty:   .asciiz  "  "                     #空格
output_3:  .asciiz "\n The detail after sort is:\n"     #排序后的数组数据
num:  .word 0             
      .space 1024                             #定义一个整型数组及大小
string:  .space 1024                           #定义字符串数组及大小
   .globl main 
   .text
main:   la  $a0,start
        li $v0,4
        syscall           #初始提示串
        la  $a0,string 
        li  $a1,1024
        li $v0,8
        syscall         #输入字符串
        move $t0,$a0
        li $s0,0x20          #空格
        li $s1,0x0a           #换行
        la  $a0,num           #数组初地址
        move $t1,$a0
        li $a0,0
        li $t2,0
        addi  $sp,$sp,-12
        sw  $t1,0($sp)
        sw  $t0,4($sp)
        sw  $ra,8($sp)          #利用栈保护相关数值
        jal  change1        #将字符串转换为数值并储存
        lw  $ra,8($sp)
        lw  $t0,4($sp)
        lw  $t1,0($sp)
        addi  $sp,$sp,12         #恢复
        la  $a0,output_1
        li $v0,4
        syscall
        move  $a0,$t2
        li  $v0,1
        syscall
        la  $a0,output_2                #输出提示串
        li $v0,4
        syscall
        addi  $sp,$sp,-12
        sw  $t1,0($sp)     
        sw  $t2,4($sp)
        sw  $ra,8($sp)
        jal  output1           #输出转换后的数值数组
        lw   $ra,8($sp)
        lw   $t2,4($sp)
        lw   $t1,0($sp)
        addi  $sp,$sp,12
        addi  $sp,$sp,-12
        sw  $t2,0($sp)    #数组大小
        sw  $t1,4($sp)    #数组初地址
        sw  $ra,8($sp)
        jal  done             #调用排序函数
        lw  $ra,8($sp)
        lw  $t1,4($sp)
        lw  $t2,0($sp)
        addi  $sp,$sp,12
        la  $a0,output_3        #输出提示
        li  $v0,4
        syscall
        jal  output1            #输出排序后的数组
        li  $v0,10                  #退出
        syscall
loop0:  sw $a0,($t1)          #存入整型数组
        addi  $t1,$t1,4       #整型数组地址加4
        addi $t2,$t2,1      #记录数组大小
        addi $t0,$t0,1      #字符串地址加1
        li $a0,0
change1: lb  $a3,($t0)           #取一个字节
        beq $a3,$s0,loop0         #为空格则到loop0
        beq  $a3,$s1,ret1         #为回车则到ret1
        beqz  $a3,ret             #为0则到ret
        mul  $a0,$a0,10          
        addi $a2,$a3,-48          #字符转换
        addu  $a0,$a0,$a2
        addi  $t0,$t0,1       #地址加一
        b  change1
done: la   $a0, num    #a0=num首地址
       addi  $t0,$t2,-1      #外循环变量t0初始化为数组长度-1
lp0:   addi $a1, $a0, 4    #外循环起点。内循环的起始比较单元初始化
       addi $t1, $t0,-1    #内循环变量t1初始化,t1=t0-1
lp1:   lw   $t2, ($a0)     #内循环起点。取出本趟比较的单元
       lw   $t3, ($a1)     #逐个取出随后的单元
       ble  $t2, $t3, next #前面的小,则什么都不做
       sw   $t2, ($a1)     #前面的大,则交换2个单元
       sw   $t3, ($a0)
next:  addi $a1, $a1, 4    #a1指向下一个单元
       addi $t1, $t1,-1    #内循环变量t1--
       bgez  $t1,lp1   #内循环结束,直到t1=0退出循环
       addi $a0, $a0, 4    #准备下一轮,a1指向下一轮比较的单元
       addi $t0, $t0,-1    #外循环变量t0--
       bgt  $t0, $0, lp0   #外循环结束,直到t0=0退出循环
       j  ret         # 返回

output1:   beqz  $t2,ret       #控制条件
           lw  $a0,($t1)
           li  $v0,1            #输出数组元素
           syscall
           addi  $t2,$t2,-1
           addi  $t1,$t1,4
           la  $a0,empty          #空格
           li $v0,4
           syscall
           b  output1
ret1:  sw  $a0,($t1)
       addi  $t2,$t2,1
       jr  $ra           #存储并返回
ret:  jr  $ra            #返回



.data
buffer: .space 1024
numbers: .word 0 : 256
count: .word 0
prompt: .asciiz "Input Numbers: "

.text
.globl main
main:
    la $a0, buffer
    li $a1, 1024
    jal readline

    la $a0, buffer
    la $a1, numbers
    jal parse

    lw $a0, count
    la $a1, numbers
    jal bubblesort

    lw $a0, count
    la $a1, numbers
    jal print_numbers

    li $v0, 10
    syscall

readline:
    li $v0, 4
    syscall

    li $v0, 8
    syscall
    jr $ra

parse:
    li $t1, 0
loop:
    lbu $t0, 0($a0)
    beqz $t0, done
    bltu $t0, '0', not_digit
    bgtu $t0, '9', not_digit
    subu $t0, $t0, '0'
    mul $t1, $t1, 10
    add $t1, $t1, $t0
    j next
not_digit:
    sw $t1, 0($a1)
    addiu $a1, $a1, 4
    sw $t1, count
    li $t1, 0
next:
    addiu $a0, $a0, 1
    j loop
done:
    jr $ra

bubblesort:
    addiu $sp, $sp, -8
    sw $a0, 0($sp)
    sw $a1, 4($sp)
    li $t0, 1
loop:
    lw $a0, 0($sp)
    lw $a1, 4($sp)
    li $t1, 0
    sw $t1, 0($sp)
    li $v0, 0
loop_inner:
    lw $t2, 0($a1)
    lw $t3, 4($a1)
    blt $t2, $t3, swap
    addiu $a1, $a1, 4
    addiu $v0, $v0, 1
    blt $v0, $a0, loop_inner
    j end
swap:
    sw $t2, 4($a1)
    sw $t3, 0($a1)
    li $t1, 1
    sw $t1, 0($sp)
end:
    lw $t0, 0($sp)
    bnez $t0, loop
    addiu $sp, $sp, 8
    jr $ra

print_numbers:
    addiu $sp, $sp, -4
    sw $a0, 0($sp)
loop:
    lw $a0, 0($sp)
    beqz $a0, done
    lw $t0, 0($a1)
    li $v0, 1
    move $a0, $t0
    syscall
    la $a0, space
    li $v0, 4
    syscall
以下是 MIPS 程序的后续部分:

```asm
    lw $a0, 0($sp)
    addiu $a0, $a0, -1
    sw $a0, 0($sp)
    addiu $a1, $a1, 4
    j loop
done:
    addiu $sp, $sp, 4
    jr $ra

space: .asciiz " "
.end main

以下是使用mips汇编语言实现冒泡排序的代码,可以在Mars模拟器中运行:

该程序使用冒泡排序算法对一个包含10个元素的数组进行排序,排序结果将存储在原数组中。具体实现过程如下:

.data
array: .word 5, 2, 8, 1, 9, 3, 7, 4, 6, 0  # 待排序的数组
len: .word 10  # 数组长度
 .text
.globl main
 main:
    la $t0, array  # $t0为数组首地址
    lw $t1, len  # $t1为数组长度
    addi $t1, $t1, -1  # 数组长度减1
     # 外层循环,执行n-1次
    li $t2, 0  # $t2为循环计数器
outer_loop:
    beq $t2, $t1, end  # 如果循环计数器等于数组长度-1,则跳出循环
     # 内层循环,执行n-i-1次
    li $t3, 0  # $t3为循环计数器
inner_loop:
    beq $t3, $t1  # 如果循环计数器等于数组长度,则跳出循环
    sll $t4, $t3, 2  # 计算数组下标偏移量
    add $t4, $t0, $t4  # 计算元素地址
    lw $t5, ($t4)  # 加载元素值
    sll $t6, $t3, 2  # 计算下一个元素的地址偏移量
    addi $t6, $t6, 4
    add $t6, $t0, $t6  # 计算下一个元素的地址
    lw $t7, ($t6)  # 加载下一个元素的值
    ble $t5, $t7, no_swap  # 如果当前元素小于等于下一个元素,则不交换
    sw $t7, ($t4)  # 否则,交换元素值
    sw $t5, ($t6)
no_swap:
    addi $t3, $t3, 1  # 循环计数器加1
    j inner_loop  # 继续内层循环
     addi $t2, $t2, 1  # 循环计数器加1
    j outer_loop  # 继续外层循环
 end:
    li $v0, 10  # 退出程序
    syscall

  1. .data 段定义待排序的数组 array 和数组长度 len
  2. .text 段定义 main 函数;
  3. 将数组首地址存储在寄存器$t0中,将数组长度存储在寄存器$t1中;
  4. 使用两层循环实现冒泡排序算法,外层循环执行n-1次,内层循环执行n-i-1次;
  5. 在内层循环中,依次比较相邻的两个元素,如果当前元素小于等于下一个元素,则不交换,否则交换两个元素的值;
  6. 在每次外层循环结束后,循环计数器$t2加1,继续下一次循环;
  7. 在程序结束时,调用系统调用 syscall 退出程序。
    注意,该程序仅作为示例,实际使用时需要根据具体情况进行修改和优化。

冒泡排序代码

# 这段代码的功能是将一个数字子串转换为多个数值,并存储在一个数组中

.data
inputString: .space 100     # 存储输入的数字子串
nums: .word 10              # 存储转换后的数字,最多支持10个数字

.text
# 将输入的数字子串转化为多个int型数字, 并存储在数组中
readNumbers:
    li $v0, 8           # 从输入缓冲区读取字符串
    la $a0, inputString # 字符串存储到 inputString 中
    li $a1, 100         # 指定最多读取 100 个字符
    syscall

    move $s7, $ra       # 把 $ra 存储在 $s7 中,解决子程序栈帧嵌套问题

    # 开始将数字子串转化为数字
    la $s0, inputString # $s0 存储当前数字子串的地址
    la $s1, nums        # $s1 存储 nums 数组的地址
    li $t0, 0           # $t0 存储当前处理到的数字的个数
    li $t1, 0           # $t1 存储当前数字子串的值

convertLoop:
    lb $t2, 0($s0)      # 从数字子串中读取当前字符
    beqz $t2, endConvert # 如果读取到了字符串末尾,就跳转到 endConvert 处

    # 如果读取到的字符是空格,则将 $t1 的值存储到 nums 数组,并重置 $t1 的值。
    # 如果读取到的字符不是空格,则将 $t2 的值减去 '0' 的值,因为 ASCII 码中 '0' 的值是 48。
    # 然后将 $t1 左移一位,再将 $t2 的值加上去,这样就可以把 $t2 与 $t1 拼接起来。
    beq $t2, 0x20, appendNum  # 如果读取到的字符是空格,就跳转到 appendNum 处
    subu $t2, $t2, 0x30       # 如果读取到的字符不是空格,就减去 '0' 的值
    sll $t1, $t1, 1           # 将 $t1 左移一位,相当于 $t1 = $t1 * 2
    addu $t1, $t1, $t2        # 将 $t2 的值加到 $t1 上,相当于 $t1 = $t1 + $t2
    j convertLoop

appendNum:
    sw $t1, 0($s1)           # 把当前数字存储到 nums 数组中
    addiu $s1, $s1, 4        # 将指针向后移动一个 int 的长度
    addiu $t0, $t0, 1        # 把当前处理的数字个数加 1
    beq $t0, 10, endConvert  # 如果已经读取到了 10 个数字,就跳转到 endConvert 处
    li $t1, 0                # 重置 $t1 的值为 0
    j convertLoop

endConvert:
    move $ra, $s7            # 把 $ra 的值恢复,保证不打破子程序栈帧
    jr $ra

# 这段代码的功能是冒泡排序
bubbleSort:
    la $s0, nums         # $s0 存储 nums 数组的地址
    li $t0, 10           # $t0 存储 nums 数组的大小
    li $t2, 1            # $t2 存储当前排序的轮数,初始化为 1
    li $t3, 0            # $t3 存储是否发生交换的标记,初始化为 0

sortLoop:
    li $t1, 0           # $t1 存储当前处理到的数字的下标,初始化为 0

innerLoop:
    addu $s1, $s0, $t1  # $s1 存储当前数字的地址
    addiu $t1, $t1, 4   # 将数字的下标加 1,向后遍历数字
    beq $t1, $t0, checkSwap   # 如果已经处理完了 nums 数组中的所有数字,就跳转到 checkSwap 处

    # 如果当前数字比下一个数字大,就交换它们的位置,并将标记 $t3 设为 1。交换时采用 xor 操作,效率更高。
    lw $t4, 0($s1)      # 读取当前数字的值
    lw $t5, 0($s1)($s0) # 读取下一个数字的值
    slt $t6, $t4, $t5   # 判断是否需要交换
    beqz $t6, innerLoop  # 如果不需要交换,就继续遍历下一个数字
    xor $t4, $t4, $t5   # 将两个数字进行交换
    xor $t5, $t4, $t5
    xor $t4, $t4, $t5
    sw $t4, 0($s1)      # 存储交换后的数字
    sw $t5, 0($s1)($s0)

    li $t3, 1           # 将标记 $t3 设为 1,表示发生了交换
    j innerLoop

checkSwap:
    beqz $t3, endSort   # 如果本轮排序没有发生交换,就跳转到 endSort 处

    addiu $t2, $t2, 1   # 将当前轮数加 1
    li $t3, 0           # 重置标记 $t3 的值为 0
    j sortLoop

endSort:
    jr $ra

# 这段代码的功能是输出数组中的每个数
outputNumbers:
    la $s0, nums        # $s0 存储 nums 数组的地址
    li $t0, 10          # $t0 存储 nums 数组的长度
    li $t1, 0           # $t1 存储当前输出到的数字的下标,初始化为 0

outputLoop:
    addu $s1, $s0, $t1  # $s1 存储当前数字的地址
    lw $a0, 0($s1)      # 读取当前数字的值
    li $v0, 1           # 设置系统调用代码为 1,表示输出一个整数
    syscall

    addiu $t1, $t1, 4   # 将数字下标加 1,向后遍历数字
    beq $t1, $t0, endOutput   # 如果已经输出了所有数字,就跳转到 endOutput 处

    li $a0, 0x20        # 输出一个空格
    li $v0, 11          # 设置系统调用代码为 11,表示输出一个字符
    syscall

    j outputLoop

endOutput:
    li $a0, 0x0a        # 输出一个换行符
    li $v0, 11          # 设置系统调用代码为 11,表示输出一个字符
    syscall

    jr $ra

# main 函数
main:
    li $v0, 4           # 设置系统调用代码为 4,表示输出一个字符串
    la $a0, InputMsg    # 输出 "Input Numbers: "
    syscall

    jal readNumbers    # 调用子程序,读取输入的数字并存储到 nums 数组中

    jal bubbleSort     # 调用子程序,对 nums 数组进行冒泡排序

    li $v0, 4          # 设置系统调用代码为 4,表示输出一个字符串
    la $a0, OutputMsg  # 输出 "Output Numbers: "
    syscall

    jal outputNumbers  # 调用子程序,输出排序后的数字

    li $v0, 10         # 设置系统调用代码为 10,表示退出程序
    syscall

    .data
    InputMsg: .asciiz "Input Numbers: "
    OutputMsg: .asciiz "Output Numbers: "