Skip to content

Commit 9f6ddcf

Browse files
committed
Add basic calculator implementation using stack
1 parent 492b47d commit 9f6ddcf

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.thealgorithms.stacks;
2+
3+
import java.util.Stack;
4+
5+
/**
6+
* Utility class to evaluate a basic arithmetic expression containing
7+
* non-negative integers, '+', '-', parentheses '(', ')', and spaces.
8+
*
9+
* <p>The evaluation is done using two stacks:
10+
* one for operands and one for operators.
11+
*
12+
* <p>This class cannot be instantiated.</p>
13+
*/
14+
public final class BasicCalculatorUsingStack {
15+
16+
private BasicCalculatorUsingStack() {
17+
}
18+
19+
/**
20+
* Evaluates a mathematical expression.
21+
*
22+
* @param expression the input expression
23+
* @return the evaluated result
24+
* @throws IllegalArgumentException if the expression is null or empty
25+
*/
26+
public static int evaluate(String expression) {
27+
if (expression == null || expression.isEmpty()) {
28+
throw new IllegalArgumentException("Expression must not be null or empty.");
29+
}
30+
31+
Stack<Integer> operands = new Stack<>();
32+
Stack<Character> operators = new Stack<>();
33+
34+
for (int i = 0; i < expression.length(); i++) {
35+
char current = expression.charAt(i);
36+
37+
if (current == ' ') {
38+
continue;
39+
}
40+
41+
if (Character.isDigit(current)) {
42+
int number = 0;
43+
while (i < expression.length() && Character.isDigit(expression.charAt(i))) {
44+
number = number * 10 + (expression.charAt(i) - '0');
45+
i++;
46+
}
47+
i--;
48+
operands.push(number);
49+
} else if (current == '(') {
50+
operators.push(current);
51+
} else if (current == ')') {
52+
while (!operators.isEmpty() && operators.peek() != '(') {
53+
applyOperation(operands, operators);
54+
}
55+
operators.pop(); // remove '('
56+
} else if (current == '+' || current == '-') {
57+
if (isUnaryMinus(expression, i)) {
58+
operands.push(0);
59+
}
60+
while (!operators.isEmpty() && operators.peek() != '(') {
61+
applyOperation(operands, operators);
62+
}
63+
operators.push(current);
64+
}
65+
}
66+
67+
while (!operators.isEmpty()) {
68+
applyOperation(operands, operators);
69+
}
70+
71+
return operands.pop();
72+
}
73+
74+
private static void applyOperation(Stack<Integer> operands, Stack<Character> operators) {
75+
int b = operands.pop();
76+
int a = operands.pop();
77+
char operator = operators.pop();
78+
operands.push(operator == '+' ? a + b : a - b);
79+
}
80+
81+
private static boolean isUnaryMinus(String expression, int index) {
82+
int j = index - 1;
83+
while (j >= 0 && expression.charAt(j) == ' ') {
84+
j--;
85+
}
86+
return j < 0 || expression.charAt(j) == '('
87+
|| expression.charAt(j) == '+'
88+
|| expression.charAt(j) == '-';
89+
}
90+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.thealgorithms.stacks;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
6+
import org.junit.jupiter.api.Test;
7+
8+
class BasicCalculatorUsingStackTest {
9+
10+
@Test
11+
void testSimpleAddition() {
12+
assertEquals(5, BasicCalculatorUsingStack.evaluate("2 + 3"));
13+
}
14+
15+
@Test
16+
void testSimpleSubtraction() {
17+
assertEquals(1, BasicCalculatorUsingStack.evaluate("3 - 2"));
18+
}
19+
20+
@Test
21+
void testWithParentheses() {
22+
assertEquals(23, BasicCalculatorUsingStack.evaluate("(1 + (4 + 5 + 2) - 3) + (6 + 8)"));
23+
}
24+
25+
@Test
26+
void testUnaryMinus() {
27+
assertEquals(-2, BasicCalculatorUsingStack.evaluate("-2"));
28+
assertEquals(1, BasicCalculatorUsingStack.evaluate("1 - (-2)"));
29+
}
30+
31+
@Test
32+
void testSpacesInExpression() {
33+
assertEquals(3, BasicCalculatorUsingStack.evaluate(" 2 + 1 "));
34+
}
35+
36+
@Test
37+
void testInvalidExpression() {
38+
IllegalArgumentException exception =
39+
assertThrows(IllegalArgumentException.class, () -> BasicCalculatorUsingStack.evaluate(""));
40+
assertEquals("Expression must not be null or empty.", exception.getMessage());
41+
}
42+
}

0 commit comments

Comments
 (0)