以这种方式给出二叉树:
.data
tree: .word a
a: .word 5, b, c
b: .word 2, d, e
c: .word 1, 0, 0
d: .word 5, f, g
e: .word 9, 0, h
f: .word 0, 0, 0
g: .word 6, i, 0
h: .word 55, 0, j
i: .word 4, 0, 0
j: .word 8, 0, 0
树看起来像这样: 所以最长的路径是经过i-g-d-b-e-h-j的7路。
所以我的问题是如何实现这个? 我需要在堆栈中使用多少空间?
我需要使用0-4到左边孩子的值4-8和右边孩子的8-12值?
我的意思是如何从根目录进入下一个孩子?
答案 0 :(得分:1)
如何移动此数据?
给定指向$a0
中节点的指针,左右指针距节点起点的4字节偏移量。 (节点结构的第一个成员似乎是一个整数,但你不需要对它做任何事情。)所以 lw $t1, 4($a0)
加载第二个结构成员(即{ {1}}),node->left
加载lw $t2, 8($a0)
。
您可以通过与零寄存器进行比较来检查NULL,即node->right
,如下所示:
0
我认为您的搜索算法应该进行树遍历,查找具有最大beq $t1, $0, left_was_zero
的节点。正常的有序遍历将考虑每个节点一次。
递归算法是显而易见的方法,但您可能希望在寄存器中保留一些持久状态,即在递归调用中将它们用作全局变量。所以你可以保持很多状态"生活"在寄存器中而不是以一个天真的C编译器的方式实际传递/返回它。我将使用全局寄存器变量表示它。
maxdepth(left) + maxdepth(right)
您可以使用实际递归来实现此功能;这可能比跟踪您是否在节点的左子树或右子树中以及在调用堆栈上使用堆栈数据结构更容易。带有返回地址的register unsigned longest_len asm("$t8") = 0;
register node* longest_root asm("$t9") = NULL;
// private helper function
// returns max depth, updates global registers along the way
static unsigned traverse(node *root) {
unsigned left_depth=0, right_depth=0;
if (root->left)
left_depth = traverse(root->left);
if (root->right)
right_depth = traverse(root->right);
unsigned sum = left_depth + right_depth;
if (sum >= longest_len) {
// update global registers
longest_len = path + 1; // path includes *this* node
longest_root = root;
}
// you can probably save an instruction somewhere by optimizing the +1 stuff between the retval and the longest_len check
int retval = left_depth + 1; // $v0
if (left_depth < right_depth)
retval = right_depth + 1; // +1 to include this node
return retval;
}
node *find_longest_path(node *tree) {
longest_len = 0;
// longest_root = NULL; // will always be overwritten
traverse(tree);
return longest_root;
}
/ jal
是一种方便的方式来跟踪要返回的块。
无论如何,这应该直接转化为MIPS asm;它甚至可能使用全局寄存器变量进行编译(使用gcc),因为我认为我使用了jr
https://gcc.gnu.org/onlinedocs/gcc/Global-Register-Variables.html