|
4 | 4 | import java.util.regex.Matcher;
|
5 | 5 | import java.util.regex.Pattern;
|
6 | 6 |
|
| 7 | +/** |
| 8 | + * Utility class for converting an infix arithmetic expression |
| 9 | + * into its equivalent postfix (Reverse Polish Notation) form. |
| 10 | + * <p> |
| 11 | + * This class provides a static method to perform the conversion, |
| 12 | + * validating balanced brackets before processing. |
| 13 | + * </p> |
| 14 | + */ |
7 | 15 | public final class InfixToPostfix {
|
| 16 | + |
8 | 17 | private InfixToPostfix() {
|
9 | 18 | }
|
10 | 19 |
|
11 |
| - public static String infix2PostFix(String infixExpression) throws Exception { |
| 20 | + /** |
| 21 | + * Converts a given infix expression string to a postfix expression string. |
| 22 | + * <p> |
| 23 | + * The method first checks if the brackets in the input expression are balanced |
| 24 | + * by calling {@code BalancedBrackets.isBalanced} on the filtered brackets. |
| 25 | + * If the brackets are not balanced, it throws an IllegalArgumentException. |
| 26 | + * </p> |
| 27 | + * <p> |
| 28 | + * Supported operators are: {@code +, -, *, /, ^} |
| 29 | + * and operands can be letters or digits. |
| 30 | + * </p> |
| 31 | + * |
| 32 | + * @param infixExpression the arithmetic expression in infix notation |
| 33 | + * @return the equivalent postfix notation expression |
| 34 | + * @throws IllegalArgumentException if the brackets in the expression are unbalanced |
| 35 | + */ |
| 36 | + public static String infix2PostFix(String infixExpression) { |
12 | 37 | if (!BalancedBrackets.isBalanced(filterBrackets(infixExpression))) {
|
13 |
| - throw new Exception("invalid expression"); |
| 38 | + throw new IllegalArgumentException("Invalid expression: unbalanced brackets."); |
14 | 39 | }
|
| 40 | + |
15 | 41 | StringBuilder output = new StringBuilder();
|
16 |
| - Stack<Character> stack = new Stack<>(); |
17 |
| - for (char element : infixExpression.toCharArray()) { |
18 |
| - if (Character.isLetterOrDigit(element)) { |
19 |
| - output.append(element); |
20 |
| - } else if (element == '(') { |
21 |
| - stack.push(element); |
22 |
| - } else if (element == ')') { |
23 |
| - while (!stack.isEmpty() && stack.peek() != '(') { |
24 |
| - output.append(stack.pop()); |
| 42 | + Stack<Character> operatorStack = new Stack<>(); |
| 43 | + |
| 44 | + for (char token : infixExpression.toCharArray()) { |
| 45 | + if (Character.isLetterOrDigit(token)) { |
| 46 | + // Append operands (letters or digits) directly to output |
| 47 | + output.append(token); |
| 48 | + } else if (token == '(') { |
| 49 | + // Push '(' to stack |
| 50 | + operatorStack.push(token); |
| 51 | + } else if (token == ')') { |
| 52 | + // Pop and append until '(' is found |
| 53 | + while (!operatorStack.isEmpty() && operatorStack.peek() != '(') { |
| 54 | + output.append(operatorStack.pop()); |
25 | 55 | }
|
26 |
| - stack.pop(); |
| 56 | + operatorStack.pop(); // Remove '(' from stack |
27 | 57 | } else {
|
28 |
| - while (!stack.isEmpty() && precedence(element) <= precedence(stack.peek())) { |
29 |
| - output.append(stack.pop()); |
| 58 | + // Pop operators with higher or equal precedence and append them |
| 59 | + while (!operatorStack.isEmpty() && precedence(token) <= precedence(operatorStack.peek())) { |
| 60 | + output.append(operatorStack.pop()); |
30 | 61 | }
|
31 |
| - stack.push(element); |
| 62 | + operatorStack.push(token); |
32 | 63 | }
|
33 | 64 | }
|
34 |
| - while (!stack.isEmpty()) { |
35 |
| - output.append(stack.pop()); |
| 65 | + |
| 66 | + // Pop any remaining operators |
| 67 | + while (!operatorStack.isEmpty()) { |
| 68 | + output.append(operatorStack.pop()); |
36 | 69 | }
|
| 70 | + |
37 | 71 | return output.toString();
|
38 | 72 | }
|
39 | 73 |
|
| 74 | + /** |
| 75 | + * Returns the precedence level of the given operator. |
| 76 | + * |
| 77 | + * @param operator the operator character (e.g., '+', '-', '*', '/', '^') |
| 78 | + * @return the precedence value: higher means higher precedence, |
| 79 | + * or -1 if the character is not a recognized operator |
| 80 | + */ |
40 | 81 | private static int precedence(char operator) {
|
41 |
| - switch (operator) { |
42 |
| - case '+': |
43 |
| - case '-': |
44 |
| - return 0; |
45 |
| - case '*': |
46 |
| - case '/': |
47 |
| - return 1; |
48 |
| - case '^': |
49 |
| - return 2; |
50 |
| - default: |
51 |
| - return -1; |
52 |
| - } |
| 82 | + return switch (operator) { |
| 83 | + case '+', '-' -> 0; |
| 84 | + case '*', '/' -> 1; |
| 85 | + case '^' -> 2; |
| 86 | + default -> -1; |
| 87 | + }; |
53 | 88 | }
|
54 | 89 |
|
| 90 | + /** |
| 91 | + * Extracts only the bracket characters from the input string. |
| 92 | + * Supports parentheses (), curly braces {}, square brackets [], and angle brackets <>. |
| 93 | + * |
| 94 | + * @param input the original expression string |
| 95 | + * @return a string containing only bracket characters from the input |
| 96 | + */ |
55 | 97 | private static String filterBrackets(String input) {
|
56 | 98 | Pattern pattern = Pattern.compile("[^(){}\\[\\]<>]");
|
57 | 99 | Matcher matcher = pattern.matcher(input);
|
|
0 commit comments