diff --git a/src/com/bilgeadam/java/examples/paranthesis_matcher/ParenthesisMatcher.java b/src/com/bilgeadam/java/examples/paranthesis_matcher/ParenthesisMatcher.java deleted file mode 100644 index 8d0184c..0000000 --- a/src/com/bilgeadam/java/examples/paranthesis_matcher/ParenthesisMatcher.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.bilgeadam.java.examples.paranthesis_matcher; - -import java.util.Stack; - -public class ParenthesisMatcher { - private final Stack matcher; - - public ParenthesisMatcher() { - matcher = new Stack(); - } - - public void atest(){ - int i = 5; - btest(); - } - - private void btest(){ - int j = 3; - } - /** - * This method will parse the string as mathematical expression and generate result - * Assumption, only add, subtract, multiply, division - * Uses only integer - * Solves the problem using recursive approach - * @param input String to parse - * @return The mathematical result - */ - public float parseInput(String input){ - Stack bucket = new Stack(); - // Loop through each element of String - for (int i = 0; i < input.length(); i++) { - if(input.charAt(i) == '('){ - int j = input.indexOf(')',i); - float res = parseInput(input.substring(i+1, j)); - i = j; - bucket.push(res); - } - else if(Character.isDigit(input.charAt(i))){ - if (bucket.size() >=2 && !Character.isDigit((Character) bucket.peek())){ - // This will result '+', '-', '*', '/' - Character operation = (Character) bucket.pop(); - - String c = String.valueOf(bucket.pop()); - Float operandOne = Float.parseFloat(c); - - c = String.valueOf(input.charAt(i)); - Float operandTwo = Float.parseFloat(c); - - switch (operation){ - case '+': - bucket.push(operandOne + operandTwo); - break; - case '-': - bucket.push(operandOne - operandTwo); - break; - case '*': - bucket.push(operandOne * operandTwo); - break; - case '/': - bucket.push(operandOne / operandTwo); - break; - default: - throw new IllegalArgumentException("Unknown"); - } - } else - bucket.push(input.charAt(i)); - } - // this case only occurs for '+', '-', '*', '/' - else if(!Character.isAlphabetic(input.charAt(i))) - bucket.push(input.charAt(i)); - - } - - String c = String.valueOf(bucket.pop()); - return Float.parseFloat(c); - } - - public boolean verifyParenthesis(String input){ - // Loop through each element of String - for (Character c : input.toCharArray()) { - if (c.equals('(')) - matcher.push(c); - else if(c.equals(')')) { - // If my bucket is empty, the parenthesis are not matched - if (matcher.isEmpty()) - return false; - else - matcher.pop(); - } - } - - return matcher.isEmpty(); - } -} diff --git a/src/com/bilgeadam/java/examples/recursive/MathematicalExpressionParser.java b/src/com/bilgeadam/java/examples/recursive/MathematicalExpressionParser.java new file mode 100644 index 0000000..fd3c243 --- /dev/null +++ b/src/com/bilgeadam/java/examples/recursive/MathematicalExpressionParser.java @@ -0,0 +1,119 @@ +package com.bilgeadam.java.examples.recursive; + +import java.util.Stack; + +public class MathematicalExpressionParser { + // All tokens separated by space will be stored in here + private final String[] strings; + + // Current index of the strings array + private int currentIndex; + + /** + * This constructor will create a Stack to store and parse mathematical expressions + * @implSpec only +, -, *, / and {@link Integer} values, separated by space, are present in the {@code input} + * + * @param input String to parse + */ + public MathematicalExpressionParser(String input) { + strings = input.split(" "); + currentIndex = 0; + } + + /** + * This method will parse the string as mathematical expression and generate result + * @implNote Solves the problem using recursive approach + * + * @return The mathematical result as {@link Float} + */ + public float parseInput(){ + // Initialize a Stack to store mathematical expressions + Stack bucket = new Stack<>(); + + // Acquire new tokens from the string array is not empty + for (int i = currentIndex; i < strings.length; i++){ + // Recursively call itself + if (strings[i].equals("(")) { + currentIndex = ++i; + bucket.push((String.valueOf(parseInput()))); + i = currentIndex; + } + // This means end of the current call, return + else if (strings[i].equals(")")) { + currentIndex = i; + return Float.parseFloat(consumeBucket(bucket)); + } + // Check if current string is a number or not + else if (isNumeric(strings[i])){ + // If the bucket does not have a number, then it means the current expressions needs to be parsed. + if (!bucket.isEmpty() && !isNumeric(bucket.peek())) { + char operand = bucket.pop().charAt(0); + float left = Float.parseFloat(bucket.pop()); + bucket.push( + String.valueOf( + parseSimpleExpression(left, Float.parseFloat(strings[i]), operand))); + } else // Store current number + bucket.push(strings[i]); + } else // Means it is only +, -, *, / symbol + bucket.push(strings[i]); + + } + + return Float.parseFloat(consumeBucket(bucket)); + } + + /** + * This method consumes the stack and generate only the last result + * + * @param currentStack Current Stack + * @return the last result of mathematical expression + */ + private String consumeBucket(Stack currentStack){ + // Consume remaining mathematical expressions if left any + while (currentStack.size() > 2){ + float right = Float.parseFloat(currentStack.pop()); + char operand = currentStack.pop().charAt(0); + float left = Float.parseFloat(currentStack.pop()); + currentStack.push( + String.valueOf( + parseSimpleExpression(left, right, operand))); + } + + return currentStack.pop(); + } + /** + * This method will parse current mathematical expression and generate a result + * @param operandOne Left operand + * @param operandTwo Right operand + * @param operator + or - or * or / + * @return the result + */ + private float parseSimpleExpression(float operandOne, float operandTwo, char operator){ + switch (operator){ + case '+': + return operandOne + operandTwo; + case '-': + return operandOne - operandTwo; + case '*': + return operandOne * operandTwo; + case '/': + return operandOne / operandTwo; + default: + throw new IllegalArgumentException("Unknown symbol: " + operator); + } + } + /** + * This method verifies given string is a {@link Double} number or not + * + * @param input The string to be parsed + * @return true if {@code input} is {@link Double}, false otherwise + */ + private boolean isNumeric(String input){ + try { + Double.parseDouble(input); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/src/com/bilgeadam/java/examples/recursive/RecursiveImplementations.java b/src/com/bilgeadam/java/examples/recursive/RecursiveImplementations.java new file mode 100644 index 0000000..7f56521 --- /dev/null +++ b/src/com/bilgeadam/java/examples/recursive/RecursiveImplementations.java @@ -0,0 +1,34 @@ +package com.bilgeadam.java.examples.recursive; + +public class RecursiveImplementations { + /** + * This method calls {@code methodB} within itself + */ + public int methodA(){ + // Method specific variable + int i = 5; + + // Call another method, the other method cannot see variable 'i' + methodB(); + + return i; + } + + /** + * This method cannot see the variables stored in {@code methodA} + */ + private void methodB(){ + int j = 3; + System.out.println("Local variable j = " + j); + } + + /** + * Calculates the factorial of given number + * + * @param i The value to be calculated + * @return the factorial result + */ + public int factorial(int i){ + return (i == 1) ? i : i * factorial(i-1); + } +} diff --git a/src/com/bilgeadam/java/examples/stacks/ParenthesisMatcher.java b/src/com/bilgeadam/java/examples/stacks/ParenthesisMatcher.java new file mode 100644 index 0000000..7d2ae8c --- /dev/null +++ b/src/com/bilgeadam/java/examples/stacks/ParenthesisMatcher.java @@ -0,0 +1,35 @@ +package com.bilgeadam.java.examples.stacks; + +import java.util.Stack; + +public class ParenthesisMatcher { + private final Stack matcher; + + public ParenthesisMatcher() { + matcher = new Stack<>(); //Create an empty stack + } + + + /** + * This method verifies that each "(" is matched with a ")" while ignoring all other {@link Character} of the {@code input} + * @param input String to be validated + * @return true if parenthesis are matched, false otherwise + */ + public boolean verifyParenthesis(String input){ + // Loop through each element of String + for (Character c : input.toCharArray()) { + if (c.equals('(')) + matcher.push(c); + else if(c.equals(')')) { + // If my bucket is empty, the parenthesis are not matched + if (matcher.isEmpty()) + return false; + else + matcher.pop(); + } + } + + // There should be nothing left in the stack for parenthesis to be matched. + return matcher.isEmpty(); + } +} diff --git a/test/com/bilgeadam/java/examples/paranthesis_matcher/ParenthesisMatcherTest.java b/test/com/bilgeadam/java/examples/paranthesis_matcher/ParenthesisMatcherTest.java deleted file mode 100644 index 99ba24e..0000000 --- a/test/com/bilgeadam/java/examples/paranthesis_matcher/ParenthesisMatcherTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.bilgeadam.java.examples.paranthesis_matcher; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class ParenthesisMatcherTest { - ParenthesisMatcher testClass; - - @BeforeEach - void setUp() { - testClass = new ParenthesisMatcher(); - } - - @AfterEach - void tearDown() { - testClass = null; - } - - @Test - void verifyParenthesis() { - String input = "(2+3)*(2-5)"; - - assertEquals(true, testClass.verifyParenthesis(input)); - } - - - @Test - void verifyParenthesis2() { - String input = "(2+3)*(2-5"; - - assertEquals(false, testClass.verifyParenthesis(input)); - } - - @Test - void verifyParenthesis3() { - String input = "((2+3)*(2-5)-5"; - - assertEquals(false, testClass.verifyParenthesis(input)); - } - - - @Test - void verifyParenthesis4() { - String input = "(((2+3)-(2-5))-(5-6))"; - - assertEquals(true, testClass.verifyParenthesis(input)); - } - - - @Test - void verifyParenthesis5() { - String input = "(((2+3)-2-5))-(5-6))"; - - assertEquals(false, testClass.verifyParenthesis(input)); - } - - @Test - void parseInput() { - String input = "2+3-5+(3*2)"; - - assertEquals(6.0, testClass.parseInput(input)); - } - - @Test - void atest() { - testClass.atest(); - } -} \ No newline at end of file diff --git a/test/com/bilgeadam/java/examples/recursive/MathematicalExpressionParserTest.java b/test/com/bilgeadam/java/examples/recursive/MathematicalExpressionParserTest.java new file mode 100644 index 0000000..dcdb074 --- /dev/null +++ b/test/com/bilgeadam/java/examples/recursive/MathematicalExpressionParserTest.java @@ -0,0 +1,42 @@ +package com.bilgeadam.java.examples.recursive; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class MathematicalExpressionParserTest { + MathematicalExpressionParser testClass; + + @AfterEach + void tearDown() { + testClass = null; + } + + /** + * Here all test cases are created + * @return inputs and results for each test case + */ + private static Stream testParameters(){ + return Stream.of( + Arguments.arguments("2 + 3", "5"), + Arguments.arguments("( 2 + 3 )", "5"), + Arguments.arguments("3 - ( 2 + 3 )", "-2"), + Arguments.arguments("( 3 - 4 ) / ( 2 + 3 )", "-0.2"), + Arguments.arguments("( 3 - ( 2 * 3 ) ) / 5", "-0.6"), + Arguments.arguments("( 3 - 1 ) + ( 2 + 3 )", "7") + ); + } + + @ParameterizedTest(name = "{index} => parseInput({0}) should return {1}") + @MethodSource("testParameters") + void parseInput(String input, String result) { + testClass = new MathematicalExpressionParser(input); + + assertEquals(Float.parseFloat(result), testClass.parseInput()); + } +} \ No newline at end of file diff --git a/test/com/bilgeadam/java/examples/recursive/RecursiveImplementationsTest.java b/test/com/bilgeadam/java/examples/recursive/RecursiveImplementationsTest.java new file mode 100644 index 0000000..739484f --- /dev/null +++ b/test/com/bilgeadam/java/examples/recursive/RecursiveImplementationsTest.java @@ -0,0 +1,31 @@ +package com.bilgeadam.java.examples.recursive; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class RecursiveImplementationsTest { + RecursiveImplementations testClass; + + @BeforeEach + void setUp() { + testClass = new RecursiveImplementations(); + } + + @AfterEach + void tearDown() { + testClass = null; + } + + @Test + void testMethods() { + assertEquals(5, testClass.methodA()); + } + + @Test + void testFactorial() { + assertEquals(6, testClass.factorial(3)); + } +} \ No newline at end of file diff --git a/test/com/bilgeadam/java/examples/stacks/ParenthesisMatcherTest.java b/test/com/bilgeadam/java/examples/stacks/ParenthesisMatcherTest.java new file mode 100644 index 0000000..b8eb09d --- /dev/null +++ b/test/com/bilgeadam/java/examples/stacks/ParenthesisMatcherTest.java @@ -0,0 +1,58 @@ +package com.bilgeadam.java.examples.stacks; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ParenthesisMatcherTest { + ParenthesisMatcher testClass; + + @BeforeEach + void setUp() { + testClass = new ParenthesisMatcher(); + } + + @AfterEach + void tearDown() { + testClass = null; + } + + @Test + void verifyParenthesisOne() { + String input = "(2+3)*(2-5)"; + + assertTrue(testClass.verifyParenthesis(input)); + } + + @Test + void verifyParenthesisTwo() { + String input = "(2+3)*(2-5"; + + assertFalse(testClass.verifyParenthesis(input)); + } + + @Test + void verifyParenthesisThree() { + String input = "((2+3)*(2-5)-5"; + + assertFalse(testClass.verifyParenthesis(input)); + } + + @Test + void verifyParenthesisFour() { + String input = "(((2+3)-(2-5))-(5-6))"; + + assertTrue(testClass.verifyParenthesis(input)); + } + + + @Test + void verifyParenthesisFive() { + String input = "(((2+3)-2-5))-(5-6))"; + + assertFalse(testClass.verifyParenthesis(input)); + } +} \ No newline at end of file