CuriousFolk.me

How to Evaluate Postfix Expression using Stack Data Structure - Algorithm & Code

May 06, 2015

Expression Evaluation

In the previous article, we learned how to convert an Infix expression to a Postfix expression using the Stack data structure. Now, let’s take the next logical step — evaluating the Postfix expression to get the final result.

Why do we need to evaluate Postfix expressions? Because computers find it much easier to evaluate Postfix (or Prefix) expressions compared to Infix expressions due to the absence of parentheses and operator precedence rules during evaluation.


What is Expression Evaluation?

Expression evaluation is the process of computing the result of a mathematical expression. When we have a Postfix expression like 5 3 +, we need to evaluate it to get the result 8.

The beauty of Postfix notation is that:

  1. We don’t need to worry about operator precedence
  2. We don’t need parentheses
  3. We can evaluate it in a single left-to-right scan

Algorithm for Postfix Expression Evaluation

The algorithm to evaluate a Postfix expression is straightforward:

  1. Create an empty stack to store operands
  2. Scan the Postfix expression from left to right
  3. For each token:
    • If the token is an operand (number), push it onto the stack
    • If the token is an operator, pop the required number of operands from the stack, apply the operator, and push the result back onto the stack
  4. After scanning all tokens, the stack will contain exactly one element — the final result

Step-by-Step Example 1: Simple Expression

Let’s evaluate a simple Postfix expression:

Postfix Expression: 5 3 +

We start with:

  1. An empty operand stack

Step 1: Read token 5 — it’s an operand, push it to the stack.

Stack
5

Step 2: Read token 3 — it’s an operand, push it to the stack.

Stack
3
5

Step 3: Read token + — it’s an operator. Pop two operands from the stack.

  • Second operand (top): 3
  • First operand: 5
  • Apply operation: 5 + 3 = 8
  • Push result back to stack
Stack
8

Final Result: 8

The Postfix expression 5 3 + evaluates to 8


Step-by-Step Example 2: Complex Expression

Let’s evaluate a more complex Postfix expression:

Postfix Expression: 5 1 2 + 4 * + 3 -

This is the Postfix equivalent of the Infix expression: 5 + ((1 + 2) * 4) - 3

We start with:

  1. An empty operand stack

Step 1: Read token 5 — operand, push to stack.

Stack
5

Step 2: Read token 1 — operand, push to stack.

Stack
1
5

Step 3: Read token 2 — operand, push to stack.

Stack
2
1
5

Step 4: Read token + — operator. Pop 2 and 1, compute 1 + 2 = 3, push result.

Stack
3
5

Step 5: Read token 4 — operand, push to stack.

Stack
4
3
5

Step 6: Read token * — operator. Pop 4 and 3, compute 3 * 4 = 12, push result.

Stack
12
5

Step 7: Read token + — operator. Pop 12 and 5, compute 5 + 12 = 17, push result.

Stack
17

Step 8: Read token 3 — operand, push to stack.

Stack
3
17

Step 9: Read token - — operator. Pop 3 and 17, compute 17 - 3 = 14, push result.

Stack
14

Final Result: 14

The Postfix expression 5 1 2 + 4 * + 3 - evaluates to 14


Important Note: Order of Operands

When dealing with non-commutative operators like subtraction (-) and division (/), the order of operands matters!

When we pop two operands from the stack:

  • The first pop gives us the second operand (right operand)
  • The second pop gives us the first operand (left operand)

For example, if we want to compute 10 - 3:

  • The Postfix would be: 10 3 -
  • When we encounter -, we pop 3 first, then 10
  • We compute: 10 - 3 = 7 (NOT 3 - 10)

Code Implementation in C

Here’s a complete C implementation to evaluate Postfix expressions:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_SIZE 100

// Stack structure
struct Stack {
    int top;
    int items[MAX_SIZE];
};

// Function to initialize the stack
void initStack(struct Stack* stack) {
    stack->top = -1;
}

// Function to check if stack is empty
int isEmpty(struct Stack* stack) {
    return stack->top == -1;
}

// Function to check if stack is full
int isFull(struct Stack* stack) {
    return stack->top == MAX_SIZE - 1;
}

// Function to push an element onto stack
void push(struct Stack* stack, int value) {
    if (isFull(stack)) {
        printf("Stack Overflow!\n");
        return;
    }
    stack->items[++stack->top] = value;
}

// Function to pop an element from stack
int pop(struct Stack* stack) {
    if (isEmpty(stack)) {
        printf("Stack Underflow!\n");
        return -1;
    }
    return stack->items[stack->top--];
}

// Function to evaluate a Postfix expression
int evaluatePostfix(char* expression) {
    struct Stack stack;
    initStack(&stack);
    
    int i = 0;
    
    while (expression[i] != '\0') {
        // Skip whitespace
        if (expression[i] == ' ') {
            i++;
            continue;
        }
        
        // If the character is a digit, extract the full number
        if (isdigit(expression[i])) {
            int num = 0;
            while (isdigit(expression[i])) {
                num = num * 10 + (expression[i] - '0');
                i++;
            }
            push(&stack, num);
        }
        // If the character is an operator
        else if (expression[i] == '+' || expression[i] == '-' || 
                 expression[i] == '*' || expression[i] == '/') {
            
            // Pop two operands
            int operand2 = pop(&stack);  // Second operand (top of stack)
            int operand1 = pop(&stack);  // First operand
            
            int result;
            
            switch (expression[i]) {
                case '+':
                    result = operand1 + operand2;
                    break;
                case '-':
                    result = operand1 - operand2;
                    break;
                case '*':
                    result = operand1 * operand2;
                    break;
                case '/':
                    if (operand2 == 0) {
                        printf("Error: Division by zero!\n");
                        return 0;
                    }
                    result = operand1 / operand2;
                    break;
            }
            
            // Push the result back onto the stack
            push(&stack, result);
            i++;
        }
        else {
            i++;  // Skip unknown characters
        }
    }
    
    // The final result is at the top of the stack
    return pop(&stack);
}

int main() {
    char expression1[] = "5 3 +";
    char expression2[] = "5 1 2 + 4 * + 3 -";
    char expression3[] = "10 3 -";
    char expression4[] = "2 3 1 * + 9 -";
    
    printf("Postfix: %s\n", expression1);
    printf("Result: %d\n\n", evaluatePostfix(expression1));
    
    printf("Postfix: %s\n", expression2);
    printf("Result: %d\n\n", evaluatePostfix(expression2));
    
    printf("Postfix: %s\n", expression3);
    printf("Result: %d\n\n", evaluatePostfix(expression3));
    
    printf("Postfix: %s\n", expression4);
    printf("Result: %d\n\n", evaluatePostfix(expression4));
    
    return 0;
}

Output:

Postfix: 5 3 +
Result: 8

Postfix: 5 1 2 + 4 * + 3 -
Result: 14

Postfix: 10 3 -
Result: 7

Postfix: 2 3 1 * + 9 -
Result: -4

Code Implementation in JavaScript

For those who prefer JavaScript, here’s the same implementation:

class Stack {
    constructor() {
        this.items = [];
    }
    
    push(element) {
        this.items.push(element);
    }
    
    pop() {
        if (this.isEmpty()) {
            return null;
        }
        return this.items.pop();
    }
    
    isEmpty() {
        return this.items.length === 0;
    }
    
    peek() {
        return this.items[this.items.length - 1];
    }
}

function evaluatePostfix(expression) {
    const stack = new Stack();
    const tokens = expression.split(' ');
    
    for (let token of tokens) {
        // Skip empty tokens
        if (token === '') continue;
        
        // If token is a number, push it to stack
        if (!isNaN(token)) {
            stack.push(parseFloat(token));
        }
        // If token is an operator
        else if (['+', '-', '*', '/'].includes(token)) {
            // Pop two operands
            const operand2 = stack.pop();  // Second operand (top)
            const operand1 = stack.pop();  // First operand
            
            let result;
            
            switch (token) {
                case '+':
                    result = operand1 + operand2;
                    break;
                case '-':
                    result = operand1 - operand2;
                    break;
                case '*':
                    result = operand1 * operand2;
                    break;
                case '/':
                    if (operand2 === 0) {
                        throw new Error("Division by zero!");
                    }
                    result = operand1 / operand2;
                    break;
            }
            
            // Push result back to stack
            stack.push(result);
        }
    }
    
    // Return the final result
    return stack.pop();
}

// Test the function
console.log("Postfix: 5 3 +");
console.log("Result:", evaluatePostfix("5 3 +"));

console.log("\nPostfix: 5 1 2 + 4 * + 3 -");
console.log("Result:", evaluatePostfix("5 1 2 + 4 * + 3 -"));

console.log("\nPostfix: 10 3 -");
console.log("Result:", evaluatePostfix("10 3 -"));

console.log("\nPostfix: 2 3 1 * + 9 -");
console.log("Result:", evaluatePostfix("2 3 1 * + 9 -"));

Output:

Postfix: 5 3 +
Result: 8

Postfix: 5 1 2 + 4 * + 3 -
Result: 14

Postfix: 10 3 -
Result: 7

Postfix: 2 3 1 * + 9 -
Result: -4

Step-by-Step Example 3: With All Four Operators

Let’s evaluate a Postfix expression that uses all four basic operators:

Postfix Expression: 6 2 / 3 + 4 2 - *

This is the Postfix equivalent of: ((6 / 2) + 3) * (4 - 2)

Step 1: Read 6 — push to stack.

Stack
6

Step 2: Read 2 — push to stack.

Stack
2
6

Step 3: Read / — pop 2 and 6, compute 6 / 2 = 3, push result.

Stack
3

Step 4: Read 3 — push to stack.

Stack
3
3

Step 5: Read + — pop 3 and 3, compute 3 + 3 = 6, push result.

Stack
6

Step 6: Read 4 — push to stack.

Stack
4
6

Step 7: Read 2 — push to stack.

Stack
2
4
6

Step 8: Read - — pop 2 and 4, compute 4 - 2 = 2, push result.

Stack
2
6

Step 9: Read * — pop 2 and 6, compute 6 * 2 = 12, push result.

Stack
12

Final Result: 12

The Postfix expression 6 2 / 3 + 4 2 - * evaluates to 12


Time and Space Complexity

Time Complexity: O(n)

  • We scan the expression once from left to right
  • Each push and pop operation takes O(1) time
  • Therefore, the overall time complexity is O(n), where n is the length of the expression

Space Complexity: O(n)

  • In the worst case, all tokens could be operands
  • The stack could hold up to n/2 elements (for expressions like 1 2 3 4 5 + + + +)
  • Therefore, the space complexity is O(n)

Common Errors and Edge Cases

When implementing Postfix evaluation, be mindful of these common issues:

  1. Division by Zero: Always check if the divisor is zero before performing division.

  2. Stack Underflow: Ensure the stack has enough operands before popping. An invalid Postfix expression might cause this.

  3. Invalid Expression: After evaluation, the stack should contain exactly one element. If it contains more, the expression was malformed.

  4. Operand Order: Remember that for subtraction and division, the order matters. The second pop gives you the first operand.


Summary

In this article, we learned:

  1. How to evaluate Postfix expressions using a Stack data structure
  2. The simple algorithm: push operands, apply operators by popping operands
  3. The importance of operand order for non-commutative operators
  4. Complete code implementations in both C and JavaScript
  5. Time and space complexity analysis

Combined with the previous article on Infix to Postfix conversion, you now have the complete toolkit to:

  1. Take any Infix expression
  2. Convert it to Postfix notation
  3. Evaluate the Postfix expression to get the result

This is exactly how calculators and compilers work behind the scenes!


Practice Problems

Try evaluating these Postfix expressions by hand:

  1. 8 2 3 * +
  2. 7 2 * 4 +
  3. 5 9 8 + 4 6 * - 7 + *
  4. 15 7 1 1 + - / 3 * 2 1 1 + + -

Hope you now understand how to evaluate Postfix expressions using the Stack data structure!