Evaluate reverse Polish notation

Push numbers; on an operator, pop two and push the result. Two details decide whether it is correct: the first value popped is the right-hand operand, which only matters for - and /; and the division truncates toward zero, which is int(a / b) and not a // b.

Stacks & queuesCoding problemMedium

Step through it

What to watch

  • Numbers accumulate; an operator is the only thing that shrinks the stack.
  • 13 / 5 becomes 2, not 2.6 — integer division, truncated.
  • Exactly one value remains, and that is the result.

Say this out loud

"A stack. Numbers get pushed; an operator pops two operands, applies itself and pushes the result. The order matters - the first pop is the right operand - and for division I use int(a / b) rather than //, because Python floors and postfix expects truncation toward zero. At the end the stack holds exactly one value."

Overview

Reverse Polish notation places each operator after its operands, so parentheses and precedence rules are unnecessary. A stack stores values until an operator consumes the most recent operands and pushes the result.

Run it

The evaluator, on two standard expressions.

1Python
Output

Pop order, with the case that hides the bug printed beside the case that reveals it.

2Python
Output

The division that differs on negatives, and the two ways an expression can be malformed.

3Python
Output

Why postfix needs no parentheses

In infix, 4 + 13 / 5 is ambiguous without precedence rules, and (4 + 13) / 5 needs brackets to say the other thing. Postfix encodes the order in the token sequence itself, so there is nothing left to disambiguate. And that is why it evaluates with a stack and no parser.

The rule is mechanical. A number has no dependencies, so it waits on the stack. An operator's operands are always the most recent unconsumed values. This is exactly what "top of the stack" means.

The two lines that are wrong in most first attempts

Pop order. b = pop(). A = pop() and then a - b. Getting it backwards gives the right answer for + and * and the negated or reciprocal answer for - and / — which is why the bug survives the first test case anybody tries.

Division. Python's // floors. So -7 // 2 is -4. Postfix, like C and like every version of this problem, truncates toward zero and wants -3. int(a / b) gives that; math.trunc(a / b) says it more by name. For positive operands the two agree, so this is another bug that only appears on the test case with a negative number in it.

What the stack depth tells you

The depth is a validity check you get for free. Every number adds one; every binary operator removes one net. So a well-formed expression of n numbers and n−1 operators ends at depth 1.

Two failure modes follow. And an interviewer may ask for both. Popping from an empty stack means an operator with too few operands — malformed. Finishing with more than one value means numbers that nothing consumed, which is also malformed. Checking both is three lines and is the difference between a solution and a reliable one.

The follow-up: converting from infix

"How would you get postfix in the first place?" The shunting-yard algorithm. And it is the same structure twice: one stack for operators, one output list. Numbers go straight to the output; an operator pops every operator of higher or equal precedence before pushing itself; brackets push and pop. Worth being able to name even if you are not asked to write it. It is the reason postfix exists as an intermediate form.

Edge cases to raise

Volunteering these is most of what separates a correct answer from a good one.

Division by zero. int(a / b) raises ZeroDivisionError. Decide whether that propagates or becomes a domain error of your own, and say so rather than discovering it.

Multi-digit and negative literals. int(t) handles both, but a tokeniser that splits on characters rather than whitespace will turn -4 into an operator and a number.

A single number is a valid expression. ["42"] should return 42. And a loop that requires at least one operator will not.

Sources and next steps

How the code works

The evaluator, the two orderings that separate right from wrong, and the division that differs on negative operands.

How the code works

  1. b = stack.pop(); a = stack.pop()The order is the answer to half this question. b came off first, so it is the right-hand operand of a - b.
  2. int(a / b)Truncation toward zero. a // b floors, which differs for exactly the cases where one operand is negative — and agrees everywhere else, which is what makes it a late-arriving bug.
  3. if len(stack) != 1: raiseThe depth is a free validity check. One value means well-formed; more means numbers nothing consumed.
  4. evaluate_swapped(["3","4","+"])Printed beside the correct version to make the point that + and * cannot detect the swap. Test with subtraction or you will not find it.

Change one thing

  • Add % and **. The modulo has the same sign disagreement as division, and exponentiation is the first operator here that is not commutative or associative.
  • Feed it ["2", "0", "/"]. Decide whether the right answer is an exception or a sentinel, and say which before you write it.

Where this runs

Real CPython, compiled to WebAssembly and running on your own machine — nothing is uploaded. The first run takes a few seconds while the interpreter downloads; after that it is immediate. Need more room, or want to paste your own attempt? Use the Python compiler.

Check yourself

0 of 4

Answer without scrolling back up.

  1. In a - b, which value was popped first?

  2. Why int(a / b) rather than a // b?

  3. What does the stack depth at the end tell you?

  4. Why does postfix need no parentheses?

Cheat sheet

Evaluate reverse Polish notation

Evaluate a postfix expression with a stack. Push operands, pop for each operator, and trace through examples like 4 13 5 / + step by step.

INTERVIEW · vizlearn.in/interview/evaluate-reverse-polish-notation.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.