在 Java 中解析算术表达式并从中构建树

2022-09-01 03:37:55

我需要一些帮助来创建自定义树,给出一个算术表达式。例如,假设您输入此算术表达式:

(5+2)*7

结果树应如下所示:

    *
   / \
  +   7
 / \
5   2

我有一些自定义类来表示不同类型的节点,即PlusOp,LeafInt等。我不需要计算表达式,只需创建树,以便以后可以对其执行其他功能。此外,负运算符“-”只能有一个子项,要表示“5-2”,必须将其输入为 5 + (-2)。

需要对表达式进行一些验证,以确保每种类型的运算符都具有正确的 no。的参数/子项,每个左括号都附有一个右括号。

另外,我应该提到我的朋友已经编写了将输入字符串转换为令牌堆栈的代码,如果这对这有帮助的话。

我将不胜感激任何帮助。谢谢:)

(我读到你可以编写一个语法并使用antlr / JavaCC等来创建解析树,但我不熟悉这些工具或编写语法,所以如果这是你的解决方案,如果你能为他们提供一些有用的教程/链接,我将不胜感激。


答案 1

假设这是某种家庭作业,你想自己做。

我曾经做过一次,你需要一个堆栈

因此,您为该示例所做的是:

    parse    what to do?                Stack looks like
      (      push it onto the stack     (
      5      push 5                     (, 5
      +      push +                     (, 5, +
      2      push 2                     (, 5, +, 2
      )      evaluate until (           7            
      *      push *                     7, *
      7      push 7                     +7, *, 7
      eof    evaluate until top         49

像“5”或“+”这样的符号可以只存储为字符串或简单对象,或者您可以将+存储为+()对象而不设置值,并在计算时设置它们。

我认为这也需要一个优先级顺序,所以我将描述它是如何工作的。

在以下情况下:5 + 2 * 7

你必须推5推+推2下一个op是更高的优先级,所以你也推它,然后推7。当您遇到 )或文件结尾或具有较低或相等优先级的运算符时,您开始将堆栈计算为上一个(或文件的开头)。

因为你的堆栈现在包含 5 + 2 * 7,所以当你评估它时,你首先弹出 2 * 7 并将生成的 *(2,7) 节点推送到堆栈上,然后再次评估堆栈上的前三个事物(5 + *节点),以便树正确显示。

如果它以另一种方式排序:5 * 2 + 7,您将推动直到到达具有“5 * 2”的堆栈,然后您将点击较低的优先级+,这意味着评估您现在拥有的内容。你将 5 * 2 计算到一个 *节点中并推送它,然后你继续按 + 和 3,这样你就有了 *node + 7,此时你将对其进行评估。

这意味着您有一个“最高电流优先级”变量,该变量在推送 +/-时存储 1,在推送 * 或 / 时存储 2,为“^”存储 3。这样,您只需测试变量,以查看下一个运算符的优先级是否为 < = 当前优先级。

如果“)”被认为是优先级4,您可以将其视为其他运算符,除了它删除了匹配的“(”,较低的优先级不会。


答案 2

我想回应Bill K.的答案,但我缺乏在那里添加评论的声誉(这真的是这个答案所属的地方)。你可以把这看作是比尔·K.答案的补充,因为他的回答有点不完整。缺少的考虑因素是运算符关联性;即,如何解析表达式,例如:

49 / 7 / 7

根据划分是左还是右关联,答案是:

49 / (7 / 7) => 49 / 1 => 49

(49 / 7) / 7 => 7 / 7 => 1

通常,除法和减法被认为是左结合的(即上面的情况二),而幂是右结合的。因此,当您遇到一系列具有相同优先级的运算符时,如果它们保持关联,则希望按顺序分析它们;如果它们保持关联,则按相反顺序分析它们。这只决定了你是推送还是弹出到堆栈,所以它不会使给定的算法过于复杂,它只是增加了连续运算符具有相等优先级的情况(即,如果左关联,则评估堆栈,如果右关联,则推到堆栈)。


推荐