算法 - 如何求解算术表达式DAG?

时间:2012-04-12 10:18:31

标签: algorithm data-structures graph tree directed-acyclic-graphs

Algorithm Design Manual中有两个相关的消息。

基本上,我知道如何解决第一个消费税,但我不知道如何解决第二个使用第一个解决方案作为提示

算术表达式树的消息

arithmetic expression tree

  

上面是算术表达式树。假设一个算术   表达式以树形式给出。每个叶子是一个整数,每个   内部节点是标准算术运算之一   (+, - ,*,/)。例如,表达式2 + 3 * 4 +(3 * 4)/ 5是   由上图中的树表示。给出一个O(n)算法   评估这样一个表达式,其中树中有n个节点。

好的,这并不难。我的解决方案是这样的:

    public float evaluate() {
        return evaluate(root);
    }

    private float evaluate(Node_EX _node) {
        if (_node.left == null || _node.right == null)
            return Float.parseFloat(_node.key);
        String op = _node.key;
        if (op == "+") {
            return evaluate(_node.left) + evaluate(_node.right);
        } else if (op == "-") {
            return evaluate(_node.left) - evaluate(_node.right);
        } else if (op == "*") {
            return evaluate(_node.left) * evaluate(_node.right);
        } else {
            return evaluate(_node.left) / evaluate(_node.right);
        }
    }

我只是使用递归方式来解析结果的表达式树。

算术表达式的消除 DAG

arithmetic expression dag

  

假设算术表达式是DAG(有向无环的)   图表)删除了常见的子表达式。每个叶子是一个整数和   每个内部节点都是标准的算术运算之一   (+, - ,*,/)。例如,表达式2 + 3 * 4 +(3 * 4)/ 5是   由上图中的DAG表示。给出O(n + m)算法   用于评估这样的DAG,其中有n个节点和m个边缘   DAG。 提示:修改树案例的算法来实现   期望的效率。

好的,说明中有这样的提示:提示:修改树箱的算法以达到理想的效率。

实际上,我对这个提示很困惑。对于典型的树相关事物,我们通常可以使用递归来解决。但是,如果这是一个图形,我的第一个直观是使用BFS或DFS来解决它。那么如何将BFS或DFS与树相关联,尽管DFS实际上是递归的?

2 个答案:

答案 0 :(得分:11)

我相信,为了达到理想的效率,问题是要避免重新评估已经访问过的树的部分内容。一旦到达并评估了DAG中的某个子树(树中的每个节点代表以该节点为根的子树),您就可以存储结果值并将其与该子树相关联。然后,当您再次访问它时,您可以检查是否已预先计算该值并仅检索它而不是再次对其进行评估。

有许多不同的方法可以存储和检索这些值,一个简单的方法是修改节点的结构以允许可缓存的结果。

答案 1 :(得分:2)

可以使用给定DAG上的DFS解决问题。

  • 我们将保存对airthmetic表达的常见部分的重新计算。

  • 例如:在执行DFS时,将从(/)节点重新遇到*。 (/)和*之间的边是交叉边,这意味着已经评估了(*)的左右子树。因此,我们将利用这一点,并将节省重新计算。

  • 但要实现这一点,我们需要在节点上保存操作的结果。

  • 复杂度为O(n + m),因为它是正常的DFS遍历,有一些额外的内存用于存储中间结果。

希望这有帮助。