This page explains every major part of the Infix Conversion project. All code shown is the real code from this project.
The Shunting Yard algorithm, invented by Edsger Dijkstra, is a method for parsing mathematical expressions specified in infix notation. It can be used to produce output in Reverse Polish Notation (Postfix) or Prefix notation. The algorithm uses a stack to hold operators and pushes operands directly to the output.
First, the user's input string is broken down into a list of meaningful tokens (operands, operators, parentheses) using a regular expression. This gives us an array of items to iterate through.
// From script.js โ Tokenizer helper const tok = (e) => e.match(/[a-zA-Z0-9]+|[\+\-\*\/\^\(\)]/g) || []; let t = tok(exp);
If doing Prefix conversion (via InfixToPrefix), we
process the expression backwards. We reverse the token array and
swap left and right parentheses, then run the algorithm.
// From InfixToPrefix() โ Reverse tokens & swap parenthesis t = t.reverse().map((c) => (c === "(" ? ")" : c === ")" ? "(" : c));
We initialize an out array for results and an
ops stack for operations. As we iterate over each
token:
โข Operands (letters/numbers) are pushed
directly to the output.
โข Open Parentheses
( are pushed to the stack.
โข
Close Parentheses ) trigger popping from the
stack to the output until the matching open parenthesis is
found.
let out = [], ops = []; t.forEach((c) => { switch (true) { case isOp(c): out.push(c); // Operand straight to output break; case c === "(": ops.push(c); // Open parenthesis to stack break; case c === ")": // Pop until we discover '(' while (ops.length && ops[ops.length - 1] !== "(") out.push(ops.pop()); ops.pop(); // Discard the '(' itself break;
If the token falls into the default case, it must
be an operator (like +, *,
^). We check its precedence against the operator at
the top of the stack. Because Prefix evaluates right-to-left for
powers (associativity), its conditional check differs slightly
from Postfix.
default: while (ops.length && ops[ops.length - 1] !== "(") { let top = ops[ops.length - 1]; // Postfix Check: // if (p[top] > p[c] || (p[top] === p[c] && c !== "^")) // Prefix Check: // if (p[top] > p[c] || (p[top] === p[c] && c === "^")) if (cond) out.push(ops.pop()); else break; } ops.push(c); // Finally push the new operator break; } });
Once the loop is finished, we empty any remaining operators from the stack into the output array. If doing Prefix, this is where we reverse the entire output array back to normal so it reads correctly. The user sees the final joined string on the screen!
// Flush remaining operators to the output while (ops.length) out.push(ops.pop()); // Postfix finish: // return out.join(" "); // Prefix finish: // return out.reverse().join(" ");
| Phase | Time Complexity |
|---|---|
| Tokenization | O(n) |
| Iteration | O(n) |
| Array Reverse (Prefix) | O(n) |