Repository: TheAlgorithms/Java
Pull request #5409 (2024-08-26 21:46:43)

refactor: `PostfixToInfix`
Class cleanup.
Readability improvements.
Added tests.

<!--
Thank you for your contribution!
In order to reduce the number of notifications sent to the maintainers, please:
- create your PR as draft, cf. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests,
- make sure that all of the CI checks pass,
- mark your PR as ready for review, cf. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request#marking-a-pull-request-as-ready-for-review
-->

<!-- For completed items, change [ ] to [x] -->

- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.
- [x] All new code is formatted with `clang-format -i --style=file path/to/your/file.java`

codecov-commenter: ## [Codecov](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5409?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) Report
Attention: Patch coverage is `78.57143%` with `3 lines` in your changes missing coverage. Please review.
> Project coverage is 49.08%. Comparing base [(`c5b73ec`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/c5b73ec742d0522d65331ee02a143f54041845ed?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) to head [(`0457e78`)](https://app.codecov.io/gh/TheAlgorithms/Java/commit/0457e78d7bcfb51a3ae63bd2d3847d54f6d52a5b?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).

| [Files](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5409?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) | Patch % | Lines |
|---|---|---|
| [.../java/com/thealgorithms/stacks/PostfixToInfix.java](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5409?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Fcom%2Fthealgorithms%2Fstacks%2FPostfixToInfix.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms#diff-c3JjL21haW4vamF2YS9jb20vdGhlYWxnb3JpdGhtcy9zdGFja3MvUG9zdGZpeFRvSW5maXguamF2YQ==) | 78.57% | [2 Missing and 1 partial :warning: ](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5409?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##             master    #5409      +/-   ##
============================================
+ Coverage     48.85%   49.08%   +0.22%     
- Complexity     3039     3051      +12     
============================================
  Files           524      524              
  Lines         15256    15227      -29     
  Branches       2900     2891       -9     
============================================
+ Hits           7454     7474      +20     
+ Misses         7494     7441      -53     
- Partials        308      312       +4     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/TheAlgorithms/Java/pull/5409?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TheAlgorithms).


Patch:
diff --git a/src/main/java/com/thealgorithms/stacks/PostfixToInfix.java b/src/main/java/com/thealgorithms/stacks/PostfixToInfix.java
index 118a3df3..a8f98ac5 100644
--- a/src/main/java/com/thealgorithms/stacks/PostfixToInfix.java
+++ b/src/main/java/com/thealgorithms/stacks/PostfixToInfix.java
@@ -20,81 +20,64 @@ public final class PostfixToInfix {
     private PostfixToInfix() {
     }
 
+    /**
+     * Determines if a given character is a valid arithmetic operator.
+     *
+     * @param token the character to check
+     * @return true if the character is an operator, false otherwise
+     */
     public static boolean isOperator(char token) {
-        switch (token) {
-        case '+':
-        case '-':
-        case '/':
-        case '*':
-        case '^':
-            return true;
-        default:
-            return false;
-        }
+        return token == '+' || token == '-' || token == '/' || token == '*' || token == '^';
     }
 
+    /**
+     * Validates whether a given string is a valid postfix expression.
+     *
+     * A valid postfix expression must meet these criteria:
+     * 1. It should have at least one operator and two operands.
+     * 2. The number of operands should always be greater than the number of operators at any point in the traversal.
+     *
+     * @param postfix the postfix expression string to validate
+     * @return true if the expression is valid, false otherwise
+     */
     public static boolean isValidPostfixExpression(String postfix) {
-        /* Postfix expression length should NOT be less than 3 */
-        if (postfix.length() < 3) {
-            return false;
+        if (postfix.length() == 1 && (Character.isAlphabetic(postfix.charAt(0)))) {
+            return true;
         }
 
-        /* First two characters should NOT be operators */
-        if (isOperator(postfix.charAt(0))) {
-            return false;
-        }
-        if (isOperator(postfix.charAt(1))) {
-            return false;
+        if (postfix.length() < 3) {
+            return false; // Postfix expression should have at least one operator and two operands
         }
 
         int operandCount = 0;
         int operatorCount = 0;
 
-        /* Traverse the postfix string to check if --> Number of operands = Number of operators + 1
-         */
-        for (int i = 0; i < postfix.length(); i++) {
-            char token = postfix.charAt(i);
-
+        for (char token : postfix.toCharArray()) {
             if (isOperator(token)) {
                 operatorCount++;
                 if (operatorCount >= operandCount) {
-                    return false;
+                    return false; // Invalid: more operators than operands at any point
                 }
             } else {
-                if (operatorCount == 0) {
-                    operandCount++;
-                    continue;
-                }
-
-                if (operandCount != operatorCount + 1) {
-                    return false;
-                }
-
-                /* Operand count is set to 2 because:-
-                 *
-                 * 1) the previous set of operands & operators combined have become a single valid
-                 * expression, which could be considered/assigned as a single operand.
-                 *
-                 * 2) the operand in the current iteration.
-                 */
-                operandCount = 2;
-
-                /* Reset operator count */
-                operatorCount = 0;
+                operandCount++;
             }
         }
 
-        return (operandCount == operatorCount + 1);
+        return operandCount == operatorCount + 1;
     }
 
+    /**
+     * Converts a valid postfix expression to an infix expression.
+     *
+     * @param postfix the postfix expression to convert
+     * @return the equivalent infix expression
+     * @throws IllegalArgumentException if the postfix expression is invalid
+     */
     public static String getPostfixToInfix(String postfix) {
-        String infix = "";
-
         if (postfix.isEmpty()) {
-            return infix;
+            return "";
         }
 
-        /* Validate Postfix expression before proceeding with the Infix conversion */
         if (!isValidPostfixExpression(postfix)) {
             throw new IllegalArgumentException("Invalid Postfix Expression");
         }
@@ -102,43 +85,18 @@ public final class PostfixToInfix {
         Stack<String> stack = new Stack<>();
         StringBuilder valueString = new StringBuilder();
 
-        String operandA;
-        String operandB;
-        char operator;
-
-        for (int index = 0; index < postfix.length(); index++) {
-            char token = postfix.charAt(index);
-
+        for (char token : postfix.toCharArray()) {
             if (!isOperator(token)) {
                 stack.push(Character.toString(token));
-                continue;
+            } else {
+                String operandB = stack.pop();
+                String operandA = stack.pop();
+                valueString.append('(').append(operandA).append(token).append(operandB).append(')');
+                stack.push(valueString.toString());
+                valueString.setLength(0);
             }
-
-            operator = token;
-            operandB = stack.pop();
-            operandA = stack.pop();
-
-            valueString.append('(');
-
-            valueString.append(operandA);
-            valueString.append(operator);
-            valueString.append(operandB);
-
-            valueString.append(')');
-
-            stack.push(valueString.toString());
-            valueString.setLength(0);
         }
 
-        infix = stack.pop();
-        return infix;
-    }
-
-    public static void main(String[] args) {
-        assert getPostfixToInfix("ABC+/").equals("(A/(B+C))");
-        assert getPostfixToInfix("AB+CD+*").equals("((A+B)*(C+D))");
-        assert getPostfixToInfix("AB+C+D+").equals("(((A+B)+C)+D)");
-        assert getPostfixToInfix("ABCDE^*/-").equals("(A-(B/(C*(D^E))))");
-        assert getPostfixToInfix("AB+CD^/E*FGH+-^").equals("((((A+B)/(C^D))*E)^(F-(G+H)))");
+        return stack.pop();
     }
 }


Test patch:
diff --git a/src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java b/src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java
new file mode 100644
index 00000000..a018865e
--- /dev/null
+++ b/src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.stacks;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class PostfixToInfixTest {
+
+    @ParameterizedTest
+    @MethodSource("provideValidPostfixToInfixTestCases")
+    void testValidPostfixToInfixConversion(String postfix, String expectedInfix) {
+        assertEquals(expectedInfix, PostfixToInfix.getPostfixToInfix(postfix));
+    }
+
+    static Stream<Arguments> provideValidPostfixToInfixTestCases() {
+        return Stream.of(Arguments.of("A", "A"), Arguments.of("ABC+/", "(A/(B+C))"), Arguments.of("AB+CD+*", "((A+B)*(C+D))"), Arguments.of("AB+C+D+", "(((A+B)+C)+D)"), Arguments.of("ABCDE^*/-", "(A-(B/(C*(D^E))))"), Arguments.of("AB+CD^/E*FGH+-^", "((((A+B)/(C^D))*E)^(F-(G+H)))"));
+    }
+
+    @Test
+    void testEmptyPostfixExpression() {
+        assertEquals("", PostfixToInfix.getPostfixToInfix(""));
+    }
+
+    @Test
+    void testNullPostfixExpression() {
+        assertThrows(NullPointerException.class, () -> PostfixToInfix.getPostfixToInfix(null));
+    }
+}