我试着理解这段代码的作用:
.section .text
.section .data
A: .long 3
.quad B
.quad C
.quad D
.quad 0
B: .long 10
.quad E
.quad F
.quad 0
C: .long 22
.quad 0
D: .long 17
.quad G
.quad 0
E: .long 85
.quad 0
F: .long 2
.quad 0
G: .long 8
.quad 0
.global _start
_start:
mov $17, %esi
mov $A, %rdi
call func
movq $1, %rdi
sub %rax, %rdi
movq $60, %rax
syscall
func:
push %rbp
movq %rsp, %rbp
cmpl %esi, (%rdi)
jne next
mov $1, %rax
jmp end
next:
mov $0, %r10
test:
cmpq $0, 4(%rdi, %r10, 8)
je fail
push %rdi
push %r10
mov 4(%rdi, %r10, 8), %rdi
call func
pop %r10
pop %rdi
cmpq $0, %rax
jne finish
inc %r10
jmp test
finish:
mov $1, %rax
jmp end
fail:
mov $0, %rax
end:
leave
ret
据我所知,它试图确定“17”是否出现在数据部分。(使用X),但看起来这取决于测试部分。我们是从A到B,然后E,F,再回到C,最后是D?最后的值是多少?我试着把它“翻译”成C,到目前为止我有:
int func(Node* root, int X){
if(root->data == null)
return 0;
Node *son == root->sons;
while(son != null){
if(son->data == 17)
return 1;
son += 1;
}
return 0;
}
它看起来正确吗?
1条答案
按热度按时间wmomyfyw1#
继续在C版本上工作,因为在将算法转换为汇编代码之前知道你想让程序做什么确实很有帮助。
正如Jester所指出的,C语言版本永远不会搜索E、F或G,因为它只在A之后的一个级别上进行搜索,A枚举了B、C、D --因此,这些 * 将 * 被搜索,但E、F、G * 不会 *。
在您的尝试中,您已写入一行:
这是一个类型不匹配,因为
data
是一个int
,即您要搜索的int
,而作为一个int
,它不能接受值null
,所以可能应该跳过此条件测试。您已经声明了
Node *son
,并且在son++
中递增。这也是一个类型不匹配,因为root->sons
是一个内联数组,并且它的元素是节点指针,所以数组实际上是指向子指针的指针。对于您的代码,
son++
将以sizeof(Node)
递增,这是完全错误的,因为这些是密集封装的指针,而不是节点。您希望它是
Node **sons = root->sons;
-这样sons++
将以sizeof(Node*)
递增,这正是您想要的。另外,因为你使用了
Node*son = root->sons
,所以在获取那些子指针的元素时缺少了一个解引用,当使用Node **sons = root->sons;
时,你可以看到它被寻址了--我们可以使用Node *son = *sons;
来完成这个解引用。递归算法在这里是有帮助的和适当的,因为被搜索的树是递归数据结构,所以也是相当自然的。
上面的算法检查“root”以查看它是否匹配,如果不匹配,则继续在每个子节点上递归地运行该函数,该函数执行相同的检查并覆盖所有子节点,包括子节点的子节点。
然而,迭代解决方案可以有效地工作,尽管在算法的持续时间内需要使用一个临时的数据结构,如堆栈或列表--这是为了记录当给定的分支没有找到匹配时“回溯”到哪里。
这个版本使用一个临时数组作为堆栈来记录需要检查的节点。然后遍历堆栈直到空,查看从堆栈中出来的节点是否匹配,同时也将子节点放在堆栈中。因此,它也会搜索子节点的子节点。
(Some程序员可以在将节点压入列表之前执行
->data == X
检查,尽管这需要在压入的两个位置都执行检查。)(In另一个变体,我们可以推送
Node **
而不是Node*
。)(It在C语言中更复杂,这是因为C语言对List等泛型数据类型的处理不佳,并且缺乏我们期望C++或C#等语言能够提供的自动扩展)。