алгоритм - Как решить арифметическое выражение DAG?

В Руководстве по разработке алгоритмов есть два связанных акциза.

В принципе, я знаю, как решить первый акциз, но я не знаю, как решить второй, используя решение первого в качестве подсказки.

Удаление арифметического выражения дерево

дерево арифметических выражений

Выше показано дерево арифметических выражений. Предположим, что арифметическое выражение дано в виде дерева. Каждый лист является целым числом, а каждый внутренний узел представляет собой одну из стандартных арифметических операций (+, -, ∗, /). Например, выражение 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

арифметическое выражение dag

Предположим, что арифметическое выражение задано как DAG (направленный ациклический граф) с удаленными общими подвыражениями. Каждый лист является целым числом, а каждый внутренний узел представляет собой одну из стандартных арифметических операций (+, -, ∗, /). Например, выражение 2 + 3 ∗ 4 + (3 ∗ 4) / 5 представлено DAG на рисунке выше. Приведите алгоритм O (n + m) для оценки такого DAG, где есть n узлов и m ребер в DAG. Подсказка: измените алгоритм для случая дерева, чтобы добиться желаемой эффективности.

Хорошо, в описании есть такая подсказка: Подсказка: измените алгоритм для случая дерева, чтобы достичь желаемой эффективности.

На самом деле, этот намек меня очень сбил с толку. Для типичных вещей, связанных с деревом, мы обычно можем использовать рекурсивное решение. Однако, если это график, первым делом я должен использовать BFS или DFS для его решения. Тогда как я могу связать BFS или DFS с деревом, хотя DFS на самом деле является рекурсивным?


person Jackson Tale    schedule 12.04.2012    source источник


Ответы (2)


Я считаю, что для достижения желаемой эффективности проблема требует, чтобы вы избегали переоценки частей дерева, которые вы уже посетили. После того, как вы достигли и оценили какое-то поддерево в DAG (каждый узел в дереве представляет поддерево с корнем в этом узле), вы можете сохранить полученное значение и связать его с этим поддеревом. Затем, когда вы посетите его снова, вы можете проверить, рассчитали ли вы это значение заранее, и просто получить его, а не оценивать снова.

Есть много разных способов сохранения и извлечения этих значений, простой из которых - изменить структуру узла, чтобы обеспечить кэшируемый результат.

person Felix Fung    schedule 12.04.2012
comment
как вы думаете, мое решение для дерева линейно? - person Jackson Tale; 12.04.2012
comment
Да, ваше решение является линейным для дерева, потому что ни один узел не будет посещаться более одного раза. Но для DAG в худшем случае это просто DFS и может стать экспоненциальным. Представьте себе дерево выражения, которое было действительно высоким. DFS будет проходить очень много разных путей, чтобы добраться до листьев. - person Felix Fung; 12.04.2012
comment
DFS посещает каждый лист только один раз; он не требует экспоненциального времени. - person JeffE; 24.10.2014
comment
@JeffE, плохая формулировка с моей стороны. Я хотел только сказать, что рекурсивный алгоритм, представленный в вопросе, потребует экспоненциального времени в случае DAG. - person Felix Fung; 24.10.2014
comment
Я считаю, что этот ответ с оценкой дерева после заказа приведет к поиску в глубину (DFS). - person Josiah Yoder; 04.08.2020

Проблема может быть решена с помощью DFS на данном DAG.

  • Мы сохраним пересчеты общих частей выражения airthmetic.

  • Например: при выполнении DFS, когда * будет повторно встречаться с узла (/). Ребро между (/) и * является перекрестным, что означает, что левое и правое поддеревья (*) уже вычислены. Таким образом мы воспользуемся этим и сэкономим на пересчете.

  • Однако для этого нам нужно сохранить результаты работы на узлах.

  • Сложность составляет O (n + m), поскольку это нормальный обход DFS с некоторой дополнительной памятью, используемой для хранения промежуточных результатов.

Надеюсь это поможет.

person Sumit Trehan    schedule 18.05.2014