Напишите программу, которая производит вычисление выражения, записанного в обратной польской нотации (ОПН).
В ОПН нет ни скобок, ни приоритета операторов («умножение раньше сложения»).
Чтобы прочитать выражение, записанное в таком формате, нужно просматривать выражение строго последовательно. Вводимые значения последовательно добавляются в стек. Когда встречается символ операции, то из стека извлекаются последние положенные туда значения, с ними проделывается эта операция и результат возвращается в стек.
Если для операции важен порядок значений, с которыми она производится, то первым идёт число, лежавшее в стеке глубже. В частности, если операция — вычитание, то из предпоследнего числа в стеке вычитается последнее, а не наоборот.
Изначально стек пустой, в результате полного вычисления выражения в нём должно остаться одно значение — результат вычислений.
Первый пример следует читать так: в стек последовательно добавляются значения 7 2 3
, а затем встречаем знак операции *
. Тогда значения 2
и 3
извлекаются, перемножаются, результат 6
кладётся обратно в стек. Следующий знак извлекает из стека два оставшихся в нём значения 7
и 6
, вычитает одно из другого и кладёт результат снова в стек. Выражение закончилось, в стеке одно число — 1
, это и есть результат вычисления.
Формат ввода
Вводится одна строка, содержащая разделённые пробелами целые числа и знаки операций +
, -
, *
, которые вместе составляют корректное выражение в обратной польской нотации.
Формат вывода:
Выводится одно целое число — результат вычисления выражения.
Пример
Ввод
7 2 3 * -
Вывод
1
Ввод
10 15 - 7 *
Вывод
-35
Решение
Польский калькулятор проще всего реализовать с помощью стека (читается как стэк). К счастью, списки в python настолько гибки, что стек по сути, это когда ты добавляешь элемент в конец списка, и берешь элемент тоже из конца списка.
Считываем строку и разбиваем ее на токены (split).
Заводим пустой список stack. Будем с ним работать по правилам стека.
Пока список токенов не пустой достаем первый токен.
Если это число, то записываем его в стек. В противном случае мы имеем дело с операцией. Разбираем тип операции и в зависимости от того что это за операция достаем из стека значения.
Результат вычислений будет находиться в единственном элементе стека.
Посмотреть код
Решение
string = input()
tokens = string.split(' ')
stack = []
while tokens != []:
value = tokens.pop(0)
if value.isdigit():
stack.append(int(value))
else:
match value:
case '+':
stack.append(stack.pop() + stack.pop())
case '-':
stack.append(stack.pop(-2) - stack.pop())
case '*':
stack.append(stack.pop() * stack.pop())
case '/':
stack.append(stack.pop(-2) / stack.pop())
print(stack[-1])
Как вам такой вариант решения?
spis = input().split()
stack = []
x = 1
while spis != []:
if spis[0].isdigit():
stack.append(int(spis.pop(0)))
else:
oper = spis.pop(0)
if oper == ‘-‘:
stack.append(int(stack.pop(-2) – stack.pop()))
elif oper == ‘+’:
stack.append(int(stack.pop() + stack.pop()))
elif oper == ‘*’:
stack.append(int(stack.pop() * stack.pop()))
elif oper == ‘/’:
stack.append(int(stack.pop(-2) // stack.pop()))
elif oper == ‘~’:
stack.append(int(stack.pop() * -1))
elif oper == ‘!’:
for i in range(1, stack.pop() + 1):
x = x * i
stack.append(x)
elif oper == ‘#’:
stack.append(stack[-1])
elif oper == ‘@’:
stack.append(stack.pop(-3))
print(stack[0])
В целом это примерно то, с чего начинались мои решения этой задачи, как набросок решения. Проблемы у этого варианта две:
Надо постоянно держать в голове порядок элементов в pop() что снижает читабельность, например, в операциях деления и вычитания, и особенно это касается оператора @.
Надо в каждом if/elif проводить операции по извлечению данных из стека.
Это конечно вкусовщина, но мне кажется, что структурированное всегда лучше неструктурированного. Это и в дзене python упоминается во втором пункте.
Но в строках оно короче.
Приветствую. Всегда сравниваю своё решение с вашим, чтобы улучшить качество написания кода (недавно начал обучение по пайтон). Возвращаясь к сути, решил эту задачу по принципу, описанному предыдущим комментатором. Однако в очередной раз, зайдя сюда для сверки, не понял ваш код. Перечитав параграфы хэндбука не нашёл упоминаний чего-то, что помогло бы понять смысл “match value”, “case”. Судя по структуре – это те же условные операторы, только в чём разница? Спасибо ♥
Этот оператор встречался в материале про условия.
В наиболее распространенном случае он позволяет сравнить значение с какими-то константами, но этим его использование не ограничивается. Правда для других применений, нужно знать и понимать python чуть в большем объеме, чем этот хендбук.
Добрый вечер, благодарю за ваш труд. Подскажите, для чего создан список operators?
Спасибо.
Здравствуйте. Остался по недосмотру в процессе эволюции. Некоторые строки, которые должны отправиться под нож страшно сопротивляются забвению.
На самом деле было более универсальное решение, отголоски которого можно найти в следующей задаче (там этот список разделен на три).
Но в процессе подготовки решений для этого ресурса, я максимально упростил код и упустил этот список из виду.
Спасибо, что обратили внимание.