MIPS彙編:冒泡排序


推薦入門教程:【十分鐘教會你彙編】MIPS編程入門


我是先寫出C++冒泡排序的代碼,然後再將之手動轉爲彙編代碼。

以下是冒泡排序的彙編代碼:

################################################
# # include <iostream>
# using namespace std;
# int main(void) {
#    int num;
#    cin >> num;
#    int* arr = new int[num];
#    for (int i = 0; i < num; i++) {
#        cin >> arr[i];
#    }
#    for (int i = 0; i < num-1; i++) {
#        for (int j = 0; j+1 < num-i; j++) {
#            if (arr[j] < arr[j+1]) {
#                int temp = arr[j];
#                arr[j] = arr[j+1];
#                arr[j+1] = temp;
#            }
#        }
#    }
#    for (int i = 0; i < num; i++) {
#        cout << arr[i] << " ";
#    }
#    return 0;
# }
##################################################


.text
.globl main
main:
    la $a0,input_num_msg; # 打印字符串,提示用戶輸入待排序數組長度
    li $v0,4
    syscall

    li $v0,5   # 接收用戶收入的數組長度
    syscall

    la $t6,array     # $t6 是數組首地址
    move $t7,$zero   # $t7 是循環變量i
    move $t8,$v0       # $t8 是數組長度
    move $t9,$zero   # $t9 是循環變量j

input:               # input代碼塊用於完成數組元素的輸入
    la $a0,input_int_msg  # 打印字符串,提示用戶輸入數組的元素
    li $v0,4
    syscall

    li $v0,5
    syscall

    move $t0,$t7     # 此處類似於C/C++中指針訪問數組元素的方法
    mul $t0,$t0,4    # 數組元素所佔字節數*循環變量+數組的起始地址=數組[循環變量]
    addu $t1,$t0,$t6
    sw $v0,0($t1)

    addi $t7,$t7,1
    blt $t7,$t8,input
    move $t7,$zero  # 完成輸入後將循環變量置爲0,可作爲下一個循環的循環變量,以節省寄存器

loop1:
    move $t9,$zero    # 每次執行外層循環都將內層循環的循環變量置爲0
loop2:
    move $t0,$t9      # 獲取a[i]
    mul $t0,$t0,4
    addu $t1,$t0,$t6
    lw $t2,0($t1)

    addi $t0,$t9,1    # 獲取a[i+1]
    mul $t0,$t0,4
    addu $t4,$t0,$t6
    lw $t3,0($t4)

    bge $t2,$t3,skip  # 如果a[i] > a[i+1],跳轉到skip代碼塊
    sw $t3,0($t1)   # 否則就執行下面這兩句,交換兩者的值
    sw $t2,0($t4)    

skip:
   addi $t9,$t9,1   # 內層循環變量自增,且判斷是否還滿足循環條件
   addi $t0,$t9,1   # 如果滿足,則跳轉到loop2
   sub $t1,$t8,$t7    # 如果不滿足,則將外層循環的循環變量自增,且判斷是否還滿足循環條件
   blt $t0,$t1,loop2  # 如果滿足,則跳轉到loop1
   addi $t7,$t7,1     # 如果不滿足,則不跳轉,繼續執行下面的代碼
   sub $t2,$t8,1
   blt $t7,$t2,loop1

output:
   la $a0,output_int_msg  #  打印字符串,提示用戶即將輸出程序
   li $v0,4
   syscall

   move $t7,$zero   # 將循環變量置爲0,用於下一循環,節省寄存器

print:          # 實現打印數組元素
   move $t0,$t7
   mul $t0,$t0,4
   addu $t1,$t0,$t6
   lw $a0,0($t1)
   li $v0,1
   syscall

   la $a0,seperate  # 分隔數組元素
   li $v0,4
   syscall

   addi $t7,$t7,1
   blt $t7,$t8,print   # 如果滿足循環條件,跳轉到print繼續執行循環


.data
array:.space 1024
input_num_msg:.asciiz "Please enter the number of integers:\n"
input_int_msg:.asciiz "Please enter the integers to be sorted:\n"
output_int_msg:.asciiz "The sorted numbers are:\n"
seperate:.asciiz " "

問題一:如何利用寄存器?
解決:從計組理論課瞭解到,MIPS體系中有32個寄存器,且寄存器都有各自的作用。所以我就查找資料,將這32個寄存器的作用熟記於心,這對我後續使用寄存器進行各種操作提供了莫大的幫助。

問題二:如何定義一個數組?
解決:類似於C++中動態分配內存,直接給變量申請一塊內存。

問題三:如何實現循環?
解決:定義代碼塊且指定一個名字,通過條件判斷指令實現跳轉,跳轉的目的地可以設置爲我指定的代碼塊。

問題四:如何實現數組的讀入?
解決:我使用了一個非常巧妙的方法,來實現數組每個元素的數據的存儲,即是我用循環變量乘以數組元素所佔字節大小(本次實驗爲4字節)+數組的起始地址。這有點類似於C++中利用指針訪問數組元素。(後來發現可以用左移操作符)

問題五:如何實現數組的輸出?
解決:與數組的讀入類似,只不過將sw指令改爲lw指令。

問題六:如何實現冒泡排序?
解決:有了循環的基礎,便很容易的就能實現二重循環。因此目前排序的關鍵就是如何定義元素內容的交換。我採用的是將兩個元素的值分別存入不同的寄存器中,然後滿足交換條件時,交叉存入數組中。假設這兩個數爲a,b。我將a存儲在b原本的地址,將b存儲在a原本的地址上。由於這兩個數都存在寄存器中,所以不存在覆蓋操作的情況。


以上內容皆爲本人觀點,歡迎大家提出批評和指導,我們一起探討!


發佈了146 篇原創文章 · 獲贊 268 · 訪問量 53萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章