我的MIPS汇编课程要求我将未知大小的表达式读入Parse Tree。我从来没有处理树木,所以这就是我存储价值的方式:
让我们说用户输入了表达式1 + 3 - 4(每个操作数只能是数字1-9)
我最左边的子节点将是起点,包含2个数据
1. The operand
2. Pointer to the next node (operator)
这就是我构建树的方式。我会从操作数指向操作符到下一个操作数到下一个操作符,直到没有剩余的值被读入。
我的下一个任务是以递归方式遍历树,并以infix / prefix / postfix表示法输出值。
考虑到我如何构建我的树,中缀遍历没有问题。
我坚持使用前缀。首先,我不完全理解它。
当我输出前缀中的表达式(1 + 3 - 4)时它应该出来 - + 1 3 4?我无法关注在线示例。
你还认为我的树构造得当吗?我的意思是,我无法从当前节点转到上一个节点,这意味着我总是必须从最左边的子节点开始遍历,即使我的TA说这是可行的方法,本能地听起来也不正确。 / p>
感谢您的帮助。
答案 0 :(得分:4)
您的解析树应如下所示:
'-' | +---+---+ | | '+' '4' | +---+---+ | | '1' '3'
每个节点都有两个指针。一个是左边的孩子,一个是右边的孩子。使用递归遍历时,不需要指向父节点的指针。
这是一些伪代码:
遍历中缀符号:
void traverse(Node *node) {
if (node->leftChild != 0) {
traverse(node->leftChild);
}
print(node->value);
if (node->rightChild != 0) {
traverse(node->rightChild);
}
}
遍历前缀表示法:
void traverse(Node *node) {
print(node->value);
if (node->leftChild != 0) {
traverse(node->leftChild);
}
if (node->rightChild != 0) {
traverse(node->rightChild);
}
}
遍历后缀表示法:
void traverse(Node *node) {
if (node->leftChild != 0) {
traverse(node->leftChild);
}
if (node->rightChild != 0) {
traverse(node->rightChild);
}
print(node->value);
}
您可以使用树的根节点调用traverse
方法。
您的Node
数据结构需要三个成员:
struct Node {
char value;
Node *leftChild;
Node *rightChild;
}
树的叶子将包含leftChild
和rightChild
的空指针。
有时,用更高级别的语言(无论你感到满意)编写这些内容有助于理解问题,然后将此代码“翻译”为汇编程序。我记得在这样的MIPS汇编程序中编写blocks world模拟。
答案 1 :(得分:3)
通常,您应该构造一个树,使得所有叶节点(没有子节点的节点)都是操作数,内部节点(其他所有节点)都是运算符。这应该是运算符节点的子节点是它的操作数,或者它们本身是具有操作数的运算符。如果你可以用这种方式构造一个树,形成各种符号(前缀,后缀,中缀)是相当简单的 - 你只需遵循树的预订,后序和顺序遍历,其中有众所周知的算法。
据我所知,你不是在构建一棵树,而是一个链表,这对你没有好处。你有两个不同的实体 - 操作数和操作符 - 你必须以不同的方式对待它们。
答案 2 :(得分:0)
我同意sykora所说的话。我想补充一点,在这种情况下你也可以使用堆栈。如果您的作业要求您专门使用树,那么sykora的建议最有效。但是,堆栈可能更容易编程以进行简单的表达式评估。
答案 3 :(得分:0)
这是编译的一般问题的一个实例,这是一个已解决的问题。如果您使用谷歌编写技术,您将找到与您的问题相关的各种信息。
您的图书馆应该有Aho,Sethi和Ullman的编译器:原理,技术和工具的副本。如果没有它,请求购买(这是该领域的标准工作)。 它的第一部分应该对你有所帮助。