Skip to content

Commit acb4753

Browse files
refactor: Improve readability and code clarity in InfixToPostfix (#6362)
refactor: improve InfixToPostfix Co-authored-by: Deniz Altunkapan <[email protected]>
1 parent 0a4f554 commit acb4753

File tree

2 files changed

+73
-31
lines changed

2 files changed

+73
-31
lines changed

src/main/java/com/thealgorithms/stacks/InfixToPostfix.java

Lines changed: 71 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,54 +4,96 @@
44
import java.util.regex.Matcher;
55
import java.util.regex.Pattern;
66

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+
*/
715
public final class InfixToPostfix {
16+
817
private InfixToPostfix() {
918
}
1019

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) {
1237
if (!BalancedBrackets.isBalanced(filterBrackets(infixExpression))) {
13-
throw new Exception("invalid expression");
38+
throw new IllegalArgumentException("Invalid expression: unbalanced brackets.");
1439
}
40+
1541
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());
2555
}
26-
stack.pop();
56+
operatorStack.pop(); // Remove '(' from stack
2757
} 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());
3061
}
31-
stack.push(element);
62+
operatorStack.push(token);
3263
}
3364
}
34-
while (!stack.isEmpty()) {
35-
output.append(stack.pop());
65+
66+
// Pop any remaining operators
67+
while (!operatorStack.isEmpty()) {
68+
output.append(operatorStack.pop());
3669
}
70+
3771
return output.toString();
3872
}
3973

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+
*/
4081
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+
};
5388
}
5489

90+
/**
91+
* Extracts only the bracket characters from the input string.
92+
* Supports parentheses (), curly braces {}, square brackets [], and angle brackets &lt;&gt;.
93+
*
94+
* @param input the original expression string
95+
* @return a string containing only bracket characters from the input
96+
*/
5597
private static String filterBrackets(String input) {
5698
Pattern pattern = Pattern.compile("[^(){}\\[\\]<>]");
5799
Matcher matcher = pattern.matcher(input);

src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class InfixToPostfixTest {
1212

1313
@ParameterizedTest
1414
@MethodSource("provideValidExpressions")
15-
void testValidExpressions(String infix, String expectedPostfix) throws Exception {
15+
void testValidExpressions(String infix, String expectedPostfix) {
1616
assertEquals(expectedPostfix, InfixToPostfix.infix2PostFix(infix));
1717
}
1818

@@ -28,6 +28,6 @@ void testInvalidExpressions(String infix, String expectedMessage) {
2828
}
2929

3030
private static Stream<Arguments> provideInvalidExpressions() {
31-
return Stream.of(Arguments.of("((a+b)*c-d", "invalid expression"));
31+
return Stream.of(Arguments.of("((a+b)*c-d", "Invalid expression: unbalanced brackets."));
3232
}
3333
}

0 commit comments

Comments
 (0)