Преобразование Обратной Польской Нотации
есть ли способ интерпретировать обратную польскую нотацию в "нормальную" математическую нотацию при использовании C++ или c#? Я работаю в инженерной фирме, поэтому они иногда используют RPN, и нам нужен способ его преобразования. Есть предложения?
7 ответов
да. Подумайте о том, как работает калькулятор RPN. Теперь вместо вычисления значения вы добавляете операцию в дерево. Так, например, 2 3 4 + *
, когда вы доберетесь до+, то вместо того, чтобы положить 7 в стек, вы ставите (+ 3 4)
на стеке. И точно так же, когда вы доберетесь до * (ваш стек будет выглядеть как 2 (+ 3 4) *
на этом этапе), она становится (* 2 (+ 3 4))
.
это префиксная нотация, которую вы затем должны преобразовать в infix. Обход дерева слева-направо, глубиной. Для каждого "внутреннего уровня", если приоритет оператора ниже, вам придется поместить операцию в скобки. Вот, значит, вы скажете:--4-->, потому что + имеет более низкий приоритет, чем *.
надеюсь, что это помогает!
Edit: есть тонкость (помимо Не рассмотрения унарных операций в приведенном выше): я предположил лево-ассоциативные операторы. Для право-ассоциативной (например, **
), то вы получаете разные результаты для 2 3 4 ** **
⇒ (** 2 (** 3 4))
и 2 3 ** 4 **
⇒ (** (** 2 3) 4)
.
при реконструкции инфикса из дерева оба случая показывают, что приоритет не требует квадратных скобок, но на самом деле последний случай должен быть заключен в квадратные скобки ((2 ** 3) ** 4
). Таким образом, для правоассоциативных операторов левая ветвь должна иметь более высокий приоритет (вместо более высокого или равного), чтобы избежать брекетинга.
кроме того, дальнейшие мысли заключаются в том, что вам нужны скобки для правой ветви -
и /
операторы тоже.
алгоритм шунтирования используется для преобразования Infix (т. е. алгебраического) в RPN. Это противоположно тому, чего вы хотите.
можете ли вы привести мне пример вашего ввода RPN? Я ветеран HP калькулятор пользователя/программиста. Я предполагаю, что у вас есть стек, содержащий все входы и операторы. Я бы предположил, что вам нужно восстановить дерево выражений, а затем пересечь дерево для создания формы infix.
C# не имеет встроенной поддержки для разбора обратной польской нотации (RPN).Вам нужно будет написать свой собственный парсер или найти его в интернете.
есть десятки учебников для преобразования постфиксной формы (RPN) в infix (алгебраическое уравнение). Взгляните на этой, может быть, вы найдете это полезным, и вы можете попробовать "реверсировать" его, чтобы преобразовать постфиксные выражения в форму infix, имея в виду, что для данного постфикса может быть несколько обозначений infix. Там очень мало полезных примеров, которые действительно обсуждают преобразование постфикса в infix. Вот запись из 2 частей, которую я нашел очень полезной. Он также имеет некоторый псевдо-код:
Если вы можете прочитать ruby, вы найдете некоторые хорошие решения для этого здесь
один подход заключается в том, чтобы взять пример из второй главы книга дракона что объясняет, как написать парсер для преобразования из infix в postfix нотацию и отменить его.
Если у вас есть исходный текст (строка/строки), который вы хотите преобразовать из RPN (постфиксная нотация) в "нормальную нотацию" (infix), это, безусловно, возможно (и, вероятно, не слишком сложно).
РПН была разработана для стековой машины, как способ работы был представлен ("2 + 3" -> "2 3 +") подходит, как это было на самом деле выполняются на оборудовании (нажать "2" на стек, нажимаем "3" на стек, поп-ТОП два аргумента стека и добавить их отодвинуть на стек.)
в принципе, вы хотите создать дерево синтаксиса из своего RPN, сделав 2 выражения, которые вы хотите работать на "листовых узлах" и самой операции, которая приходит позже, "родительский узел". Вероятно, это будет сделано путем рекурсивного просмотра входной строки (вы, вероятно, захотите убедиться, что подвыражения правильно заключены в скобки для дополнительной ясности, если они еще не сделаны).
Как только у вас есть это дерево синтаксиса, вы можете вывести префикс, инфикс или постфиксная нотация просто путем выполнения предзаказа, постзаказа или обхода этого дерева по порядку (опять же, скобки для ясности, если это необходимо).
можно найти дополнительную информацию здесь.
Я только что написал версию на Java, это здесь и один в Objective-C, over здесь.
возможный алгоритм: учитывая, что у вас есть стек с входом в rpn, как пользователь будет вводить его, например, 8, 9,*. Вы перебираете массив от первого до последнего и всегда удаляете текущий элемент. Этот элемент вы оцениваете. Если это операнд, вы добавляете его в стек результатов. Когда это оператор, вы дважды вставляете стек результатов (для двоичного кода операции) для операндов и записи строки результата в стек результатов.
с примером ввода "8, 9, +, 2, * " вы получаете эти значения в resultstack (квадратные скобки для обозначения отдельных элементов):
Шаг 1: [8]
Шаг 2: [8], [9]
Шаг 3: [(8 + 9)]
Шаг 4: [(8 + 9)], [2]
Шаг 5: [(8 + 9) * 2]
когда входной стек пуст, вы закончили, и единственным элементом resultStack является ваш результат. (Обратите внимание, однако, что вход может содержать несколько записей или таких, которые не имеют смысла, как ведущая операция: "+ 2 3 /".)
реализации в ссылках намеренно не используют какие-либо самодельные типы, например, для операторов или операндов, и не применяются, например, составной шаблон. Это просто чистый и простой, поэтому его можно легко понять и портировать на любой другой язык.
портировать его на C# прямо вперед.