From 2bd8c009b58d4ec79c3c82e2c998f517536baf0e Mon Sep 17 00:00:00 2001 From: unlockable Date: Thu, 2 May 2024 21:49:44 +0800 Subject: [PATCH] TA release HW1 --- 1/README.txt | 7 ++ 1/example/example.in | Bin 0 -> 20 bytes 1/example/example.out | Bin 0 -> 16 bytes 1/example/example_0.asm | 58 ++++++++++++++ 1/example/example_1.asm | 12 +++ 1/example/example_2.asm | 50 ++++++++++++ 1/example/example_3.asm | 35 +++++++++ 1/exp1/a.in | Bin 0 -> 8 bytes 1/exp1/exp1_1.cpp | 18 +++++ 1/exp1/exp1_2.cpp | 12 +++ 1/exp1/exp1_3.cpp | 15 ++++ 1/exp1/exp1_4.cpp | 18 +++++ 1/exp2/a.in | Bin 0 -> 84 bytes 1/exp2/binary_insert_sort.cpp | 58 ++++++++++++++ 1/exp2/insert_sort.cpp | 59 ++++++++++++++ 1/exp2/merge_sort.cpp | 121 +++++++++++++++++++++++++++++ 1/exp2/merge_sort_runnable.cpp | 135 +++++++++++++++++++++++++++++++++ 17 files changed, 598 insertions(+) create mode 100644 1/README.txt create mode 100644 1/example/example.in create mode 100644 1/example/example.out create mode 100644 1/example/example_0.asm create mode 100644 1/example/example_1.asm create mode 100644 1/example/example_2.asm create mode 100644 1/example/example_3.asm create mode 100644 1/exp1/a.in create mode 100644 1/exp1/exp1_1.cpp create mode 100644 1/exp1/exp1_2.cpp create mode 100644 1/exp1/exp1_3.cpp create mode 100644 1/exp1/exp1_4.cpp create mode 100644 1/exp2/a.in create mode 100644 1/exp2/binary_insert_sort.cpp create mode 100644 1/exp2/insert_sort.cpp create mode 100644 1/exp2/merge_sort.cpp create mode 100644 1/exp2/merge_sort_runnable.cpp diff --git a/1/README.txt b/1/README.txt new file mode 100644 index 0000000..b1cba71 --- /dev/null +++ b/1/README.txt @@ -0,0 +1,7 @@ +汇编大作业说明文档.docx 本次作业的具体内容说明 +汇编实验指导.pdf 为MIPS重点内容复习及大作业解释 +example/ “MARS环境安装与基础使用方法”部分参考代码 +exp1/ 作业“第一部分:基础练习”参考代码和样例数据 +exp2/ 作业“第二部分:实战应用”参考代码和样例数据 +attachment/ 实验用附件 +reference/ 参考文献 \ No newline at end of file diff --git a/1/example/example.in b/1/example/example.in new file mode 100644 index 0000000000000000000000000000000000000000..dd1dcccb192cac0a04f1e4eaa4818b1894d5427f GIT binary patch literal 20 YcmZQ!U|?uqWMC*~W? literal 0 HcmV?d00001 diff --git a/1/example/example_0.asm b/1/example/example_0.asm new file mode 100644 index 0000000..cd46aaf --- /dev/null +++ b/1/example/example_0.asm @@ -0,0 +1,58 @@ +.data +in_buff: .space 512 +out_buff: .space 512 +input_file: .asciiz "example.in" +output_file: .asciiz "example.out" +comma: .asciiz ", " +.text +la $a0, input_file #input_file һַ +li $a1, 0 #flag 0Ϊȡ 1Ϊд +li $a2, 0 #mode is ignored Ϊ0Ϳ +li $v0, 13 #13 Ϊļ syscall +syscall # 򿪳ɹ ļص$v0 + move $a0,$v0 # ļ뵽 $a0 + la $a1, in_buff #in_buff Ϊݴ + li $a2, 512 #ȡ512byte + li $v0, 14 #14 Ϊȡļ syscall + syscall + li $v0 16 #16 Ϊرļ syscall + syscall + +#ַʼѭֵΪN +la $s0, in_buff +la $s1, out_buff +lw $s2, 0($s0) +li $t0, 0 + +#ַ4 ѭ1 +for: addi $s0, $s0, 4 +addi $t0, $t0, 1 +lw $t1, 0($s0) +sw $t1, 0($s1) +addi $s1, $s1, 4 +#ӡ +move $a0, $t1 +li $v0, 1 +syscall +#ӡ +la $a0, comma +li $v0, 4 +syscall +bne $t0 $s2 for + +la $a0, output_file #output_file һַ +li $a1, 1 #flag 0Ϊȡ 1Ϊд +li $a2, 0 #mode is ignored Ϊ0Ϳ +li $v0, 13 #13 Ϊļ syscall +syscall # 򿪳ɹ ļص$v0 + +move $a0,$v0 # ļ뵽 $a0 +la $a1, out_buff #in_buff Ϊݴ +sll $s2 $s2 2 +move $a2, $s2 #д512byte +li $v0, 15 #15 Ϊдļ syscall +syscall +#ʱ$a0 еļû +#ֱӵ syscall 16 ر +li $v0 16 #16 Ϊرļ syscall +syscall diff --git a/1/example/example_1.asm b/1/example/example_1.asm new file mode 100644 index 0000000..b889dc6 --- /dev/null +++ b/1/example/example_1.asm @@ -0,0 +1,12 @@ +.data + .a + string: .asciiz "Hello World!\n" + +.text +main: + la $a0 string #载入字符串地址 + li $v0 4 #4代表打印字符串 + syscall #执行系统调用 + + li $v0 17 #17代表exit + syscall #执行系统调用 diff --git a/1/example/example_2.asm b/1/example/example_2.asm new file mode 100644 index 0000000..ae168c6 --- /dev/null +++ b/1/example/example_2.asm @@ -0,0 +1,50 @@ + .data + stringz: .asciiz "Hello World!\n" + string: .ascii "Hello World!\n" + #让array对齐到4byte边界 + .align 4 #没有这句话可能会出错 + array: .space 512 + #以下常数数组会自动对齐到对应边界 + barray: .byte 1,2,3,4 + harray: .half 1,2,3,4 + warray: .word 1,2,3,4 + + +.text +main: + la $a0 stringz #载入字符串地址 + li $v0 4 #4代表打印字符串 + syscall #执行系统调用 + + la $a0 string #载入字符串地址 + li $v0 4 #4代表打印字符串 + syscall #执行系统调用 + + la $t0 barray #载入byte数组地址 + lb $a0 0($t0) #读取barray[0] + li $v0 1 #1代表打印一个整数 + syscall #打印array[0]的数据 + lb $a0 1($t0) #读取barray[1] + li $v0 1 #1代表打印一个整数 + syscall #打印array[0]的数据 + lb $a0 2($t0) #读取barray[2] + li $v0 1 #1代表打印一个整数 + syscall #打印array[0]的数据 + lb $a0 3($t0) #读取barray[3] + li $v0 1 #1代表打印一个整数 + syscall #打印array[0]的数据 + + li $a0 10 #10代表换行符'\n' + li $v0 11 #11代表打印字符 + syscall #换个行 + + la $t0 array #载入array的地址 + li $t1 123 + sw $t1 0($t0) #在array[0]的位置存入123 + lw $a0 0($t0) #读取array[0]的数据 + li $v0 1 #1代表打印一个整数 + syscall #打印array[0]的数据 + + + li $v0 17 #17代表exit + syscall #执行系统调用 diff --git a/1/example/example_3.asm b/1/example/example_3.asm new file mode 100644 index 0000000..1aa3873 --- /dev/null +++ b/1/example/example_3.asm @@ -0,0 +1,35 @@ +.text +main: + li $v0 5 #5代表读入一个整数 + syscall #ִ执行系统调用 + move $a0 $v0 #将读入的整数作为第一个参数 + li $v0 5 #5代表读入一个整数 + syscall #ִ执行系统调用 + move $a1 $v0 #将读入的整数作为第二个参数 + + jal product #跳转到子过程product + move $a0 $v0 #将返回值赋值给$a0 + li $v0 1 #1代表打印一个整数 + syscall #ִ执行系统调用 + + li $v0 17 #17代表exit + syscall #ִ执行系统调用 + +product: + move $t0 $a0 #将第一个参数赋值给t0作为累加值 + move $t1 $a1 #将第二个参数赋值给t1作为计数器 + move $t2 $zero#结果清零 + addi $sp $sp -16 #移动栈指针到栈顶 + sw $t0 12($sp) #存入本地变量t0 + sw $t1 8($sp) #存入本地变量t1 + sw $t2 4($sp) #存入本地变量t2 + sw $ra 0($sp) #存入过程返回地址 + loop: add $t2 $t2 $t0 #结果累计t0 + sw $t2 4($sp) #存入本地变量t2 + addi $t1 $t1 -1 #计数器减一 + sw $t1 8($sp) #存入本地变量t2 + bnez $t1 loop #如果计数器不为0循环继续 + move $v0 $t2 #将结果赋给返回值 + lw $ra 0($sp) #出栈过程返回地址 + jr $ra #跳转回上一级过程 + diff --git a/1/exp1/a.in b/1/exp1/a.in new file mode 100644 index 0000000000000000000000000000000000000000..6f363cafee10987d6044d3f321d5521858979b7c GIT binary patch literal 8 NcmZQ%U|`?^VgLX*01N;C literal 0 HcmV?d00001 diff --git a/1/exp1/exp1_1.cpp b/1/exp1/exp1_1.cpp new file mode 100644 index 0000000..8e3bf5c --- /dev/null +++ b/1/exp1/exp1_1.cpp @@ -0,0 +1,18 @@ +#include "stdio.h" + +int main() { + FILE *infile ,*outfile; + int i; + int *buffer; + buffer = new int[2]; + infile = fopen("a.in", "rb"); + fread(buffer, 4, 2, infile); + fclose(infile); + outfile = fopen("a.out", "wb"); + fwrite(buffer, 4, 2, outfile); + fclose(outfile); + scanf("%d", &i); + i = i + 10; + printf("%d", i); + return 0; +} diff --git a/1/exp1/exp1_2.cpp b/1/exp1/exp1_2.cpp new file mode 100644 index 0000000..8fa5a82 --- /dev/null +++ b/1/exp1/exp1_2.cpp @@ -0,0 +1,12 @@ +#include "stdio.h" + +int main() { + int i, j, temp; + scanf("%d", &i); + scanf("%d", &j); + i = -i; + if(j < 0) j = -j; + for(temp = 0; temp < j; ++temp) i += 1; + printf("%d",i); + return 0; +} diff --git a/1/exp1/exp1_3.cpp b/1/exp1/exp1_3.cpp new file mode 100644 index 0000000..c22c25a --- /dev/null +++ b/1/exp1/exp1_3.cpp @@ -0,0 +1,15 @@ +#include "stdio.h" + +int main() { + int *a, n, i, t; + scanf("%d", &n); + a = new int [n]; + for(i = 0; i < n; i++) scanf("%d",&a[i]); + for(i = 0; i < n / 2; i++) { + t = a[i] + 1; + a[i] = a[n - i - 1] + 1; + a[n - i - 1] = t; + } + for(i = 0;i < n; i++) printf("%d", a[i]); + return 0; +} diff --git a/1/exp1/exp1_4.cpp b/1/exp1/exp1_4.cpp new file mode 100644 index 0000000..50427eb --- /dev/null +++ b/1/exp1/exp1_4.cpp @@ -0,0 +1,18 @@ +#include "stdio.h" + +int Hanoi(int n) +{ + if (n == 1) { // 基准情形 + return 1; + } else { // 递归情形 + return 2 * Hanoi(n - 1) + 1; + } +} + +int main() +{ + int n; + scanf("%d", &n); + printf("%d", Hanoi(n)); + return 0; +} \ No newline at end of file diff --git a/1/exp2/a.in b/1/exp2/a.in new file mode 100644 index 0000000000000000000000000000000000000000..2fdfd438c02588850a24e9b190a14c8b93e19e8b GIT binary patch literal 84 zcmWN}Ar687006)X7B&+j@CO5t=_qUjEjIiR8M6F right) + return left; // 递归边界,此处不统计比较次数 + int mid = (left + right) >> 1; + compare_count++; // 统计比较次数 + if (v[mid] > v[n]) + return binary_search(v, left, mid - 1, n); + else + return binary_search(v, mid + 1, right, n); +} + +// 将新的元素插入到指定位置,并将后续元素后移 +void insert(int *v, int k, int n) +{ + int i; + int tmp = v[n]; + for (i = n - 1; i >= k; i--) + { + v[i + 1] = v[i]; + } + v[k] = tmp; +} + +void binary_insertion_sort(int v[], int n) +{ + int i; + for (i = 1; i < n; i++) + { // 从第二个元素开始,依次插入到前面已经排好序的序列中 + int place = binary_search(v, 0, i - 1, i); + insert(v, place, i); + } +} + +int main() +{ + FILE *infile, *outfile; + int buffer[1001]; + infile = fopen("a.in", "rb"); + fread(buffer, 4, 1001, infile); + fclose(infile); + int N = buffer[0]; + binary_insertion_sort(&(buffer[1]), N); + buffer[0] = compare_count; + outfile = fopen("a.out", "wb"); + fwrite(buffer, 4, N + 1, outfile); + fclose(outfile); + return 0; +} diff --git a/1/exp2/insert_sort.cpp b/1/exp2/insert_sort.cpp new file mode 100644 index 0000000..0dc990c --- /dev/null +++ b/1/exp2/insert_sort.cpp @@ -0,0 +1,59 @@ +#include "stdio.h" +/* + 插入排序:将一个元素插入到一个已经排好序的序列中,使得序列依然有序。 +*/ + +// 统计比较次数 +int compare_count = 0; + +// 从后往前查找第一个比v[n]小的元素,其后一个位置即为插入位置 +int search(int v[], int n) +{ + int i; + int tmp = v[n]; + for (i = n - 1; i >= 0; i--) + { + compare_count++; // 统计比较次数 + if (v[i] <= tmp) + break; + } + return i + 1; +} + +// 将新的元素插入到指定位置,并将后续元素后移 +void insert(int *v, int k, int n) +{ + int i; + int tmp = v[n]; + for (i = n - 1; i >= k; i--) + { + v[i + 1] = v[i]; + } + v[k] = tmp; +} + +void insertion_sort(int v[], int n) +{ + int i; + for (i = 1; i < n; i++) + { // 从第二个元素开始,依次插入到前面已经排好序的序列中 + int place = search(v, i); + insert(v, place, i); + } +} + +int main() +{ + FILE *infile, *outfile; + int buffer[1001]; + infile = fopen("a.in", "rb"); + fread(buffer, 4, 1001, infile); + fclose(infile); + int N = buffer[0]; + insertion_sort(&(buffer[1]), N); + buffer[0] = compare_count; + outfile = fopen("a.out", "wb"); + fwrite(buffer, 4, N + 1, outfile); + fclose(outfile); + return 0; +} diff --git a/1/exp2/merge_sort.cpp b/1/exp2/merge_sort.cpp new file mode 100644 index 0000000..0ea9b88 --- /dev/null +++ b/1/exp2/merge_sort.cpp @@ -0,0 +1,121 @@ +#include "stdio.h" /* + +链表的归并排序的核心是将链表分成前后两段,分别排序后对两个有序链表归并,递归边界是当前链表长度为1。 +*/ + +int compare_count = 0; + +// 两个有序链表合并 , 将右链元素插入到左链中 。 +int *merge(int *l_head, int *r_head) +{ + // 这里构建一个虚拟头结点 , 方便在第一个元素前插入 。 + int *head = new int[2]; + head[1] = (int)l_head; + int *p_left = head; + int *p_right = r_head; + do + { + do + { // 寻找左链中的插入位置 + if (p_left[1] == (int)NULL) + break; + // count the number of comparisons + compare_count++; + if (((int *)p_left[1])[0] > p_right[0]) + break; + p_left = (int *)p_left[1]; + } while (1); + // 如果到达左链尾端 , 右链直接接上 + if (p_left[1] == (int)NULL) + { + p_left[1] = (int)p_right; + break; + } + int *p_right_temp = p_right; + do + { // 寻找右链待插入片段 + if (p_right_temp[1] == (int)NULL) + break; + // count the number of comparisons + compare_count++; + if (((int *)p_right_temp[1])[0] > ((int *)p_left[1])[0]) + break; + p_right_temp = (int *)p_right_temp[1]; + } while (1); + // 完成插入操作 + int *temp_right_pointer_next = (int *)p_right_temp[1]; + p_right_temp[1] = p_left[1]; + p_left[1] = (int)p_right; + p_left = p_right_temp; + p_right = temp_right_pointer_next; + if (p_right == NULL) + break; + } while (1); + int rv = head[1]; + + delete head; + return (int *)rv; +} + +// 归并排序主函数 , 先找链表中点 , 再分别排序 , 最后归并 +int *msort(int *head) +{ + if (head[1] == (int)NULL) + return head; + int *stride_2_pointer = head; + int *stride_1_pointer = head; + do + { // 通过同时进行步长为 1 和步长为 2 的跳转找中点 + if (stride_2_pointer[1] == (int)NULL) + break; + stride_2_pointer = (int *)stride_2_pointer[1]; + if (stride_2_pointer[1] == (int)NULL) + break; + stride_2_pointer = (int *)stride_2_pointer[1]; + stride_1_pointer = (int *)stride_1_pointer[1]; + } while (1); + // 拆成两个链表分别排序 , 再归并 。 + stride_2_pointer = (int *)stride_1_pointer[1]; + stride_1_pointer[1] = (int)NULL; + int *l_head = msort(head); + int *r_head = msort(stride_2_pointer); + return merge(l_head, r_head); +} + +int main() +{ + FILE *infile, *outfile; + int buffer[1001]; + infile = fopen("a.in", "rb"); + fread(buffer, 4, 1001, infile); + fclose(infile); + int N = buffer[0]; + // create a linked list + int *head = new int[2]; + head[1] = (int)NULL; + int *pointer = head; + for (int idx = 1; idx <= N; idx++) + { + pointer[1] = (int)new int[2]; + pointer = (int *)pointer[1]; + pointer[0] = buffer[idx]; + pointer[1] = (int)NULL; + } + // sort + head[1] = (int)msort((int *)head[1]); + pointer = head; + outfile = fopen("a.out", "wb"); + // 输出比较次数 + fwrite(&compare_count, 4, 1, outfile); + // wirte the sorted list to file + do + { + pointer = (int *)pointer[1]; + if (pointer == NULL) + break; + fwrite(pointer, 4, 1, outfile); + } while (1); + fclose(outfile); + // 本文件用于翻译,没有释放链表内存的操作 + return 0; +} diff --git a/1/exp2/merge_sort_runnable.cpp b/1/exp2/merge_sort_runnable.cpp new file mode 100644 index 0000000..b1521f7 --- /dev/null +++ b/1/exp2/merge_sort_runnable.cpp @@ -0,0 +1,135 @@ +#include "stdio.h" /* + +链表的归并排序的核心是将链表分成前后两段,分别排序后对两个有序链表归并,递归边界是当前链表长度为1。 + +!!!注意:此代码为可运行版本,目的是让大家检验自己的实验结果是否正确 +!!!其中的链表节点是通过结构体实现的,实际汇编的实现中指针也是32位整数,请参考另一个版本的代码(merge_sort.cpp) + +*/ + +// 统计待排序数据的比较次数 +int compare_count = 0; + +// 链表节点, 结构体实现 +struct Node +{ + int value; + Node *next; +}; + +// 两个有序链表合并,将右链元素插入到左链中 。 +Node *merge(Node *l_head, Node *r_head) +{ + // 这里构建一个虚拟头结点,方便在第一个元素前插入。 + Node *head = new Node; + head->next = l_head; + Node *p_left = head; + Node *p_right = r_head; + do + { + do + { // 寻找左链中的插入位置 + if (p_left->next == (int)NULL) + break; + compare_count++; // 统计比较次数 + if ((p_left->next)->value > p_right->value) + break; + p_left = p_left->next; + } while (1); + // 如果到达左链尾端,右链直接接上 + if (p_left->next == NULL) + { + p_left->next = p_right; + break; + } + Node *p_right_temp = p_right; + do + { // 寻找右链待插入片段 + if (p_right_temp->next == NULL) + break; + compare_count++; // 统计比较次数 + if ((p_right_temp->next)->value > (p_left->next)->value) + break; + p_right_temp = p_right_temp->next; + } while (1); + // 完成插入操作 + Node *temp_right_pointer_next = p_right_temp->next; + p_right_temp->next = p_left->next; + p_left->next = p_right; + p_left = p_right_temp; + p_right = temp_right_pointer_next; + if (p_right == NULL) + break; + } while (1); + Node *rv = head->next; + delete head; + return rv; +} + +// 归并排序主函数,先找链表中点,再分别排序,最后归并 +Node *msort(Node *head) +{ + if (head->next == NULL) + return head; + Node *stride_2_pointer = head; + Node *stride_1_pointer = head; + do + { // 通过同时进行步长为 1 和步长为 2 的跳转找中点 + if (stride_2_pointer->next == NULL) + break; + stride_2_pointer = stride_2_pointer->next; + if (stride_2_pointer->next == NULL) + break; + stride_2_pointer = stride_2_pointer->next; + stride_1_pointer = stride_1_pointer->next; + } while (1); + // 拆成两个链表分别排序 , 再归并 。 + stride_2_pointer = stride_1_pointer->next; + stride_1_pointer->next = NULL; + Node *l_head = msort(head); + Node *r_head = msort(stride_2_pointer); + return merge(l_head, r_head); +} + +int main() +{ + FILE *infile, *outfile; + int buffer[1001]; + infile = fopen("a.in", "rb"); + fread(buffer, 4, 1001, infile); + fclose(infile); + int N = buffer[0]; + Node *head = new Node; + head->next = NULL; + Node *pointer = head; + for (int idx = 1; idx <= N; idx++) + { + pointer->next = new Node; + pointer = pointer->next; + pointer->value = buffer[idx]; + pointer->next = NULL; + } + // 排序 + head->next = msort(head->next); + // 输出到文件 + pointer = head; + outfile = fopen("a.out", "wb"); + // 输出比较次数 + fwrite(&compare_count, 4, 1, outfile); + do + { + pointer = pointer->next; + if (pointer == NULL) + break; + fwrite(&(pointer->value), 4, 1, outfile); + } while (1); + fclose(outfile); + // 释放链表内存 + while (head != NULL) + { + Node *temp = head; + head = head->next; + delete temp; + } + return 0; +}