Calculator for Four Arithmetic with Brackets

It’s a typical problem to implement a four arithmetic calculator with brackets.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <cassert>
#include <stack>
#include <string_view>
#include <unordered_map>

class Solution {
public:
int calculate(std::string_view s) {
clear();

value_stack.push(0); // for some occasions that starts with a negative digit

std::size_t index = 0;
while (index < s.size()) {
// process digit with high priority
if ('0' <= s[index] && s[index] <= '9') {
int num = 0;
while (index < s.size() && ('0' <= s[index] && s[index] <= '9')) {
num = num * 10 + (s[index] - '0');
++index;
}

value_stack.push(num);
}

switch (s[index]) {
case '+':
case '-': {
process_before_addition_or_subtraction();
sign_stack.push(s[index]);
break;
}

case '*':
case '/': {
process_before_multiplication_or_division();
sign_stack.push(s[index]);
break;
}

case '(': {
sign_stack.push(s[index]);
break;
}

case ')': {
process_before_addition_or_subtraction();
sign_stack.pop();
break;
}

default: { // just skip if it's space
break;
}
}

++index;
}

process_before_addition_or_subtraction();

return value_stack.top();
}

private:
void process_before_addition_or_subtraction() {
while (!sign_stack.empty() && sign_stack.top() != '(') {
handle();
sign_stack.pop();
}
}

void process_before_multiplication_or_division() {
while (!sign_stack.empty() && (sign_stack.top() == '*' || sign_stack.top() == '/')) {
handle();
sign_stack.pop();
}
}

// Do a calculation once
void handle() {
assert(value_stack.size() >= 2);

int value2 = value_stack.top();
value_stack.pop();
int value1 = value_stack.top();
value_stack.pop();

switch (sign_stack.top()) {
case '+': {
value_stack.push(value1 + value2);
break;
}
case '-': {
value_stack.push(value1 - value2);
break;
}
case '*': {
value_stack.push(value1 * value2);
break;
}
case '/': {
assert(value2 != 0);

value_stack.push(value1 / value2); // Note that it is NOT a strict division!
break;
}
default: { // impossible in fact
break;
}
}

// Note:
// `sign_stack.pop()` is called outside `handle()` so that the iteration of loop looks more understandable.
}

void clear() {
// clear stack with trick since stack does't provide `clear()`
std::stack<int>().swap(value_stack);
std::stack<char>().swap(sign_stack);
}

std::stack<int> value_stack;
std::stack<char> sign_stack;
};

#define ASSERT(expression, expected_result) assert(solution.calculate(expression) == expected_result)

int main() {
Solution solution;

// test cases
ASSERT(" 1 + 2 ", 3); // spaces
ASSERT("1+2", 3); // addition
ASSERT("1-2", -1); // subtraction
ASSERT("2*3", 6); // multiplication
ASSERT("6/2", 3); // division
ASSERT("1+2-3*4/5", 1); // mixed expression
ASSERT("(((1)))", 1); // brackets
ASSERT("1+2-3*(4/5)", 3); // mixed expression with brackets
ASSERT("-1", -1); // start with a negative digit

// invalid test cases
// ASSERT("1/0", -1); // terminate as expected
//
// Only support division with result as an integer,
// hence multiplication and division are not actually perfectly reciprocal.
// ASSERT("1/2*2", 1);

return 0;
}

References


Calculator for Four Arithmetic with Brackets
http://wasprime.github.io/Algorithm/Design/Calculator-for-Four-Arithmetic-with-Brackets/
Author
wasPrime
Posted on
April 27, 2023
Updated on
May 3, 2023
Licensed under