【汇编】MIPS32指令集实现图的算法之拓扑排序

【汇编】MIPS32指令集实现图的算法之拓扑排序

计算机系统设计课设作业,要求用MIPS32指令集实现树或者图中的一个算法。使用的芯片是龙芯1b(ls1b)

  • 算法原理
    由某个集合上的一个偏序得到该集合上的一个全序,这个操作被称为拓扑排序。偏序和全序的定义分别如下:若集合X上的关系R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。设R是集合X上的偏序,如果对每个x,y∈X必有xRy或yRx,则称R是集合X上的全序关系。由偏序定义得到拓扑有序的操作便是拓扑排序。
  • 实现流程
  1. 在有向图中选一个没有前驱的顶点并且输出之;
  2. 从图中删除该顶点和所有以它为尾的弧。
    重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。后一种情况则说明有向图中存在环。

c语言实现的伪代码如下(严蔚敏老师的《数据结构》):
如果不太理解可以去看严蔚敏老师的《数据结构》,强推

  • 设计思路如下:
    创建邻接矩阵,输入顶点数,初始化所有顶点间无关即没有边相连接(用0表示),用1表示顶点之间相连的边。
    依次排查所有值,那我们可以发现:若顶点i与j之间存在关系,则有MGraph[i][j]=1(MGraph数组即邻接矩阵的数组)且表明i是始点,j是终点。则我们要找的即为对于i的MGraph数组内全为0(即i只可能有出度,没有入度)。
    顺便提一句,拓扑排序一般来说用到的存储节点的结构是栈,但是用汇编我指定没有现编好的那么好用的结构,只能从数组开始,因此用了实现较为简单的队列(问就是菜orz)。在实现拓扑排序的是没有问题的,不过输出的点顺序可能会与用栈有一些不同,最后的实例展示会详细解释。

代码如下:

/*
 * bsp_start.S
 *
 * created: 2022-01-24
 *  author: chear
 */

#include "regdef.h"
#include "cpu.h"
#include "asm.h"

//-----------------------------------------------------------------------------

.data
array: .word 0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0//邻接矩阵
array1: .word 0,0,0,0	//存储入度
array2:.word 0,0,0,0    //存储拓扑排序
    .text

FRAME(bsp_start,sp,0,ra)
	.set noreorder

    move    s0, ra      /* 返回地址 */

    /*
     * 用户代码插在下面

     */


.globl main

main:
    la t0,array		//t0为array数组首地址
    li t1, 4           //t1为点个数
    move t2,zero	//i
    move t3,zero	//j
    la t9,array1	//t9为array1数组首地址
    la s5,array2    //s5为array2数组首地址
    move s8,zero    //k
nop

//求各顶点出度
for1:
    move t3,zero
    b for2
    
nop

move t2,zero


for2:
//获取到a[i][j]
    mul t4,t2,4	//place(t5)=i*4+j
    addu t5,t4,t3
    mul t5,t5,4
    addu t5,t5,t0
    lw t6,0(t5)
    beq t6,1,opp1   //如果有边指向该节点
nop
    addi t3,t3,1	//j++
    blt t3,t1,for2	//j<n;
nop
    addi t2,t2,1	//i++
    blt t2,t1,for1	//i<n

opp1:	//度+1
    mul t4,t3,4
    addu t5,t4,t9
    lw t4,0(t5)
    addi t4,t4,1
    sw t4,0(t5)
    addi t3,t3,1	//j++
    blt t3,t1,for2
nop

move t3,zero

move t2,zero
for3://找出度为0的节点
    mul t4,t2,4
    addu t5,t4,t9
    lw t6,0(t5)
    beq t6,0,opp2
nop
addi t2,t2,1
blt t2,t1,for3

opp2:           //找到后将其存储在array2中
    mul t4,s8,4
    addu t5,t4,s5
    sw t2,0(t5)
    addi s8,s8,1
    addi t2,t2,1
    blt t2,t1,for3
nop


move s2,zero
move s3,zero//固定0值
move t3,zero
fo://把已选择节点相连接的节点的度减一
    mul t4,s2,4
    addu t5,t4,s5
    lw t2,0(t5)
    move t3,zero
    b for4
    nop
    addi s2,s2,1
    blt s2,s8,fo
    nop

for4://找到对应节点
    mul t4,t2,4 //place(t5)=i*4+j
    addu t5,t4,t3
    mul t5,t5,4
    addu t5,t5,t0
    lw t6,0(t5)
    beq t6,1,opp3//若t6==1,则度-1
    nop
    
    addi t3,t3,1
    blt t3,t1,for4
    nop
    addi s2,s2,1
    blt s2,s8,fo
    nop
    
opp3://array1中减一
    mul t7,t3,4
    addu t8,t7,t9
    lw t6,0(t8)
    sub t6,t6,1
    beq t6,0,opp4//度为0,入栈
    sw t6,0(t8)
    nop
    addi t3,t3,1
    blt t3,t1,for4
    nop

opp4://将新的度为0的节点插入到array2,栈中
    mul t4,s8,4
    addu t5,t4,s5
    sw t3,0(t5)
    addi s8,s8,1
    beq s8,4,print2
    addi t3,t3,1
    blt t3,t1,for4
    nop


print2:
    move t2,zero
    mul t4,t2,4
    addu t5,t4,s5
    lw s0,0(t5)
    addi t2,t2,1
    mul t4,t2,4
    addu t5,t4,s5
    lw s1,0(t5)
    addi t2,t2,1
    mul t4,t2,4
    addu t5,t4,s5
    lw s2,0(t5)
    addi t2,t2,1
    mul t4,t2,4
    addu t5,t4,s5
    lw s3,0(t5)
nop
    

	.set reorder
ENDFRAME(bsp_start)

//-----------------------------------------------------------------------------

/*
 * @@ END
 */
 

测试运行图结构为:
测试图
结果如下:

s0-s3为结果
将输出的拓扑序列存储在s0-s3寄存器中,最后输出可以看到存储的准确的拓扑序列。因为用的队列,所以输出是0,3,1,2,如果是栈的话输出是3,0,1,2。两个答案都对,具体为什么会出现差异可以想想,理论上来说图的拓扑序列原本就不止一个嘛★,°:.☆( ̄▽ ̄)/$:.°★

一些题外话:
改是一个个盯着寄存器看数值变化改的,过程真的很折磨人。整个课设持续三周,这只是第一周的任务之一。虽然最后只检查个结果,而且一如既往出现代码copy的现象,甚至我在debug的时候也在想:这真的有意义吗最后也不一定能调出来,调出来了换个测试样例可能还是错的balabala还不如copy一份别人的代码,反正我之前的其他代码也被别人copy过了啥的…最后还是在检查头天下午改出来了(只要我完成地够慢就没有人能copy我的!),完成地可能费脑费头发一点,但是自己完成和其他人完成自己copy感觉还是不一样,就酱。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值