diff --git a/data_structures/stacks/infix_to_postfix_conversion.py b/data_structures/stacks/infix_to_postfix_conversion.py index 901744309..e69706193 100644 --- a/data_structures/stacks/infix_to_postfix_conversion.py +++ b/data_structures/stacks/infix_to_postfix_conversion.py @@ -4,9 +4,26 @@ https://en.wikipedia.org/wiki/Reverse_Polish_notation https://en.wikipedia.org/wiki/Shunting-yard_algorithm """ +from typing import Literal + from .balanced_parentheses import balanced_parentheses from .stack import Stack +PRECEDENCES: dict[str, int] = { + "+": 1, + "-": 1, + "*": 2, + "/": 2, + "^": 3, +} +ASSOCIATIVITIES: dict[str, Literal["LR", "RL"]] = { + "+": "LR", + "-": "LR", + "*": "LR", + "/": "LR", + "^": "RL", +} + def precedence(char: str) -> int: """ @@ -14,7 +31,15 @@ def precedence(char: str) -> int: order of operation. https://en.wikipedia.org/wiki/Order_of_operations """ - return {"+": 1, "-": 1, "*": 2, "/": 2, "^": 3}.get(char, -1) + return PRECEDENCES.get(char, -1) + + +def associativity(char: str) -> Literal["LR", "RL"]: + """ + Return the associativity of the operator `char`. + https://en.wikipedia.org/wiki/Operator_associativity + """ + return ASSOCIATIVITIES[char] def infix_to_postfix(expression_str: str) -> str: @@ -35,6 +60,8 @@ def infix_to_postfix(expression_str: str) -> str: 'a b c * + d e * f + g * +' >>> infix_to_postfix("x^y/(5*z)+2") 'x y ^ 5 z * / 2 +' + >>> infix_to_postfix("2^3^2") + '2 3 2 ^ ^' """ if not balanced_parentheses(expression_str): raise ValueError("Mismatched parentheses") @@ -50,9 +77,26 @@ def infix_to_postfix(expression_str: str) -> str: postfix.append(stack.pop()) stack.pop() else: - while not stack.is_empty() and precedence(char) <= precedence(stack.peek()): + while True: + if stack.is_empty(): + stack.push(char) + break + + char_precedence = precedence(char) + tos_precedence = precedence(stack.peek()) + + if char_precedence > tos_precedence: + stack.push(char) + break + if char_precedence < tos_precedence: + postfix.append(stack.pop()) + continue + # Precedences are equal + if associativity(char) == "RL": + stack.push(char) + break postfix.append(stack.pop()) - stack.push(char) + while not stack.is_empty(): postfix.append(stack.pop()) return " ".join(postfix)