Skip to content

Add Infix To Prefix new algorithm with unit tests #5537

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@
* greedyalgorithms
* [ActivitySelection](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java)
* [CoinChange](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java)
* [DigitSeparation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java)
* [FractionalKnapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java)
* [GaleShapley](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/GaleShapley.java)
* [JobSequencing](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/JobSequencing.java)
Expand Down Expand Up @@ -545,6 +546,7 @@
* [DecimalToAnyUsingStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/DecimalToAnyUsingStack.java)
* [DuplicateBrackets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/DuplicateBrackets.java)
* [InfixToPostfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/InfixToPostfix.java)
* [InfixToPrefix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java)
* [LargestRectangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/LargestRectangle.java)
* [MaximumMinimumWindow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/MaximumMinimumWindow.java)
* [NextGreaterElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextGreaterElement.java)
Expand Down Expand Up @@ -759,6 +761,7 @@
* greedyalgorithms
* [ActivitySelectionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java)
* [CoinChangeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java)
* [DigitSeparationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java)
* [FractionalKnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/FractionalKnapsackTest.java)
* [GaleShapleyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/GaleShapleyTest.java)
* [JobSequencingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/JobSequencingTest.java)
Expand Down Expand Up @@ -976,6 +979,7 @@
* [DecimalToAnyUsingStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/DecimalToAnyUsingStackTest.java)
* [DuplicateBracketsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/DuplicateBracketsTest.java)
* [InfixToPostfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java)
* [InfixToPrefixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java)
* [LargestRectangleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java)
* [NextGreaterElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/NextGreaterElementTest.java)
* [NextSmallerElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/NextSmallerElementTest.java)
Expand Down
92 changes: 92 additions & 0 deletions src/main/java/com/thealgorithms/stacks/InfixToPrefix.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.thealgorithms.stacks;

import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class InfixToPrefix {
private InfixToPrefix() {
}

/**
* Convert an infix expression to a prefix expression using stack.
*
* @param infixExpression the infix expression to convert
* @return the prefix expression
* @throws IllegalArgumentException if the infix expression has unbalanced brackets
* @throws NullPointerException if the infix expression is null
*/
public static String infix2Prefix(String infixExpression) throws IllegalArgumentException {
if (infixExpression == null) {
throw new NullPointerException("Input expression cannot be null.");
}
infixExpression = infixExpression.trim();
if (infixExpression.isEmpty()) {
return "";
}
if (!BalancedBrackets.isBalanced(filterBrackets(infixExpression))) {
throw new IllegalArgumentException("Invalid expression: unbalanced brackets.");
}

StringBuilder output = new StringBuilder();
Stack<Character> stack = new Stack<>();
// Reverse the infix expression for prefix conversion
String reversedInfix = new StringBuilder(infixExpression).reverse().toString();
for (char element : reversedInfix.toCharArray()) {
if (Character.isLetterOrDigit(element)) {
output.append(element);
} else if (element == ')') {
stack.push(element);
} else if (element == '(') {
while (!stack.isEmpty() && stack.peek() != ')') {
output.append(stack.pop());
}
stack.pop();
} else {
while (!stack.isEmpty() && precedence(element) < precedence(stack.peek())) {
output.append(stack.pop());
}
stack.push(element);
}
}
while (!stack.isEmpty()) {
output.append(stack.pop());
}

// Reverse the result to get the prefix expression
return output.reverse().toString();
}

/**
* Determines the precedence of an operator.
*
* @param operator the operator whose precedence is to be determined
* @return the precedence of the operator
*/
private static int precedence(char operator) {
switch (operator) {
case '+':
case '-':
return 0;
case '*':
case '/':
return 1;
case '^':
return 2;
default:
return -1;
}
}

/**
* Filters out all characters from the input string except brackets.
*
* @param input the input string to filter
* @return a string containing only brackets from the input string
*/
private static String filterBrackets(String input) {
Pattern pattern = Pattern.compile("[^(){}\\[\\]<>]");
Matcher matcher = pattern.matcher(input);
return matcher.replaceAll("");
}
}
44 changes: 44 additions & 0 deletions src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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;

public class InfixToPrefixTest {

@ParameterizedTest
@MethodSource("provideValidExpressions")
void testValidExpressions(String infix, String expectedPrefix) throws Exception {
assertEquals(expectedPrefix, InfixToPrefix.infix2Prefix(infix));
}

@Test
void testEmptyString() {
// Assuming that an empty string returns an empty prefix or throws an exception
assertEquals("", InfixToPrefix.infix2Prefix(""));
}

@Test
void testNullValue() {
// Assuming that a null input throws a NullPointerException
assertThrows(NullPointerException.class, () -> InfixToPrefix.infix2Prefix(null));
}

private static Stream<Arguments> provideValidExpressions() {
return Stream.of(Arguments.of("3+2", "+32"), // Simple addition
Arguments.of("1+(2+3)", "+1+23"), // Parentheses
Arguments.of("(3+4)*5-6", "-*+3456"), // Nested operations
Arguments.of("a+b*c", "+a*bc"), // Multiplication precedence
Arguments.of("a+b*c/d", "+a/*bcd"), // Division precedence
Arguments.of("a+b*c-d", "-+a*bcd"), // Subtraction precedence
Arguments.of("a+b*c/d-e", "-+a/*bcde"), // Mixed precedence
Arguments.of("a+b*(c-d)", "+a*b-cd"), // Parentheses precedence
Arguments.of("a+b*(c-d)/e", "+a/*b-cde") // Mixed precedence with parentheses
);
}
}