diff --git a/src/main/java/com/thealgorithms/stacks/BasicCalculatorUsingStack.java b/src/main/java/com/thealgorithms/stacks/BasicCalculatorUsingStack.java new file mode 100644 index 000000000000..bf04309f73e4 --- /dev/null +++ b/src/main/java/com/thealgorithms/stacks/BasicCalculatorUsingStack.java @@ -0,0 +1,90 @@ +package com.thealgorithms.stacks; + +import java.util.Stack; + +/** + * Utility class to evaluate a basic arithmetic expression containing + * non-negative integers, '+', '-', parentheses '(', ')', and spaces. + * + *

The evaluation is done using two stacks: + * one for operands and one for operators. + * + *

This class cannot be instantiated.

+ */ +public final class BasicCalculatorUsingStack { + + private BasicCalculatorUsingStack() { + } + + /** + * Evaluates a mathematical expression. + * + * @param expression the input expression + * @return the evaluated result + * @throws IllegalArgumentException if the expression is null or empty + */ + public static int evaluate(String expression) { + if (expression == null || expression.isEmpty()) { + throw new IllegalArgumentException("Expression must not be null or empty."); + } + + Stack operands = new Stack<>(); + Stack operators = new Stack<>(); + + for (int i = 0; i < expression.length(); i++) { + char current = expression.charAt(i); + + if (current == ' ') { + continue; + } + + if (Character.isDigit(current)) { + int number = 0; + while (i < expression.length() && Character.isDigit(expression.charAt(i))) { + number = number * 10 + (expression.charAt(i) - '0'); + i++; + } + i--; + operands.push(number); + } else if (current == '(') { + operators.push(current); + } else if (current == ')') { + while (!operators.isEmpty() && operators.peek() != '(') { + applyOperation(operands, operators); + } + operators.pop(); // remove '(' + } else if (current == '+' || current == '-') { + if (isUnaryMinus(expression, i)) { + operands.push(0); + } + while (!operators.isEmpty() && operators.peek() != '(') { + applyOperation(operands, operators); + } + operators.push(current); + } + } + + while (!operators.isEmpty()) { + applyOperation(operands, operators); + } + + return operands.pop(); + } + + private static void applyOperation(Stack operands, Stack operators) { + int b = operands.pop(); + int a = operands.pop(); + char operator = operators.pop(); + operands.push(operator == '+' ? a + b : a - b); + } + + private static boolean isUnaryMinus(String expression, int index) { + int j = index - 1; + while (j >= 0 && expression.charAt(j) == ' ') { + j--; + } + return j < 0 || expression.charAt(j) == '(' + || expression.charAt(j) == '+' + || expression.charAt(j) == '-'; + } +} diff --git a/src/main/java/com/thealgorithms/stacks/BasicCalculatorUsingStackTest.java b/src/main/java/com/thealgorithms/stacks/BasicCalculatorUsingStackTest.java new file mode 100644 index 000000000000..b179df876228 --- /dev/null +++ b/src/main/java/com/thealgorithms/stacks/BasicCalculatorUsingStackTest.java @@ -0,0 +1,42 @@ +package com.thealgorithms.stacks; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class BasicCalculatorUsingStackTest { + + @Test + void testSimpleAddition() { + assertEquals(5, BasicCalculatorUsingStack.evaluate("2 + 3")); + } + + @Test + void testSimpleSubtraction() { + assertEquals(1, BasicCalculatorUsingStack.evaluate("3 - 2")); + } + + @Test + void testWithParentheses() { + assertEquals(23, BasicCalculatorUsingStack.evaluate("(1 + (4 + 5 + 2) - 3) + (6 + 8)")); + } + + @Test + void testUnaryMinus() { + assertEquals(-2, BasicCalculatorUsingStack.evaluate("-2")); + assertEquals(1, BasicCalculatorUsingStack.evaluate("1 - (-2)")); + } + + @Test + void testSpacesInExpression() { + assertEquals(3, BasicCalculatorUsingStack.evaluate(" 2 + 1 ")); + } + + @Test + void testInvalidExpression() { + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, () -> BasicCalculatorUsingStack.evaluate("")); + assertEquals("Expression must not be null or empty.", exception.getMessage()); + } +}