Skip to content

Commit 8b1fa1d

Browse files
committed
Calculator
1 parent fb3fdda commit 8b1fa1d

1 file changed

Lines changed: 40 additions & 71 deletions

File tree

src/main/java/algorithms/sprint2/Calculator.java

Lines changed: 40 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,43 @@
1+
import java.io.ByteArrayInputStream;
2+
import java.io.EOFException;
13
import java.io.IOException;
24
import java.io.InputStream;
35
import java.io.OutputStream;
6+
import java.nio.charset.StandardCharsets;
7+
import java.util.ArrayDeque;
8+
import java.util.Deque;
49

510
/*
6-
Принцип работы алгоритма:
7-
- Выражение в обратной польской нотации читается слева направо по токенам (разделитель — пробел).
8-
- Используется стек целых чисел.
9-
* Если токен — число, кладём его в стек.
10-
* Если токен — операция (+, -, *, /), достаём два верхних значения b и a (сначала b, потом a),
11-
вычисляем a (op) b и результат кладём обратно в стек.
12-
- После обработки всех токенов ответ — верхний элемент стека (даже если элементов больше одного).
11+
Принцип:
12+
- Читаем токены ОПН слева направо.
13+
- Число -> push в стек.
14+
- Операция -> pop b, pop a, считаем a op b, push результат.
15+
- Ответ: верх стека.
1316
1417
Корректность:
15-
- Инвариант: после обработки первых i токенов стек содержит значения всех уже полностью вычисленных
16-
подвыражений, которые по правилам ОПН должны ждать дальнейших операций.
17-
- При чтении числа инвариант сохраняется: число становится готовым операндом и помещается в стек.
18-
- При чтении операции по определению ОПН она применяется к двум ближайшим слева операндам,
19-
которые и лежат на вершине стека в нужном порядке добавления. Мы снимаем b и a и кладём результат,
20-
тем самым заменяя эти два операнда на значение их подвыражения — инвариант сохраняется.
21-
- Для деления используется Math.floorDiv(a, b), что соответствует требованию “округление вниз” (floor).
22-
По условию деления на отрицательное число нет, но a может быть отрицательным — floorDiv это корректно обрабатывает.
23-
24-
Оценка сложности:
25-
- Время: O(m), где m — число токенов (каждый токен обрабатывается за O(1)).
26-
- Память: O(s), где s — максимальный размер стека (в худшем случае O(m)).
18+
- В ОПН операция применяется к двум ближайшим слева операндам; к моменту чтения операции они лежат
19+
на вершине стека. Мы заменяем эти два значения на результат, сохраняя корректное состояние.
20+
- Деление требуется “вниз” (floor), поэтому используем Math.floorDiv(a, b).
21+
22+
Сложность:
23+
- Время O(m), m — число токенов.
24+
- Память O(s), s — максимальный размер стека (в худшем O(m)).
2725
*/
2826
public class Calculator {
2927

30-
// -------------------- SOLUTION --------------------
31-
static int evalRpn(FastIn in) throws IOException {
32-
IntStack st = new IntStack(64);
28+
private static int eval(FastIn in) throws IOException {
29+
Deque<Integer> st = new ArrayDeque<>();
30+
31+
while (true) {
32+
String t;
33+
try {
34+
t = in.next();
35+
} catch (EOFException e) {
36+
break;
37+
}
3338

34-
String tok;
35-
while ((tok = in.nextOrNull()) != null) {
36-
if (tok.length() == 1) {
37-
char op = tok.charAt(0);
39+
if (t.length() == 1) {
40+
char op = t.charAt(0);
3841
if (op == '+' || op == '-' || op == '*' || op == '/') {
3942
int b = st.pop();
4043
int a = st.pop();
@@ -54,45 +57,19 @@ static int evalRpn(FastIn in) throws IOException {
5457
continue;
5558
}
5659
}
57-
st.push(Integer.parseInt(tok));
58-
}
59-
60-
return st.peek();
61-
}
62-
63-
// -------------------- INT STACK --------------------
64-
static final class IntStack {
65-
private int[] a;
66-
private int sz;
6760

68-
IntStack(int cap) {
69-
this.a = new int[Math.max(2, cap)];
70-
this.sz = 0;
61+
st.push(Integer.parseInt(t));
7162
}
7263

73-
void push(int v) {
74-
if (sz == a.length) {
75-
int[] b = new int[a.length << 1];
76-
System.arraycopy(a, 0, b, 0, a.length);
77-
a = b;
78-
}
79-
a[sz++] = v;
80-
}
81-
82-
int pop() {
83-
return a[--sz];
84-
}
85-
86-
int peek() {
87-
return a[sz - 1];
88-
}
64+
return st.peek();
8965
}
9066

9167
// -------------------- FAST INPUT --------------------
9268
static final class FastIn {
9369
private final InputStream in;
9470
private final byte[] buf = new byte[1 << 16];
95-
private int ptr = 0, len = 0;
71+
private int ptr = 0;
72+
private int len = 0;
9673

9774
FastIn(InputStream in) {
9875
this.in = in;
@@ -109,12 +86,12 @@ private int read() throws IOException {
10986
return buf[ptr++];
11087
}
11188

112-
String nextOrNull() throws IOException {
89+
String next() throws IOException {
11390
int c;
11491
do {
11592
c = read();
11693
if (c == -1) {
117-
return null;
94+
throw new EOFException("EOF");
11895
}
11996
} while (c <= ' ');
12097

@@ -187,38 +164,30 @@ private static void run() throws Exception {
187164
FastIn in = new FastIn(System.in);
188165
FastOut out = new FastOut(System.out);
189166

190-
int ans = evalRpn(in);
167+
int ans = eval(in);
191168

192169
out.writeInt(ans);
193170
out.writeByte('\n');
194171
out.flush();
195172
}
196173

174+
// -------------------- LOCAL TESTS --------------------
197175
private static void test() throws Exception {
198176
assertEq(9, evalFromString("2 1 + 3 *"));
199177
assertEq(38, evalFromString("7 2 + 4 * 2 +"));
200-
201-
// деление “вниз”
202178
assertEq(-1, evalFromString("-1 3 /"));
203179
assertEq(-2, evalFromString("-4 3 /"));
204-
205-
// порядок операндов
206180
assertEq(2, evalFromString("10 2 4 * -"));
207-
208-
// одно число
209181
assertEq(5, evalFromString("5"));
210-
211182
System.out.println("Test OK");
212183
}
213184

214185
private static int evalFromString(String s) throws Exception {
215-
InputStream is = new java.io.ByteArrayInputStream(
216-
s.getBytes(java.nio.charset.StandardCharsets.US_ASCII)
217-
);
218-
return evalRpn(new FastIn(is));
186+
InputStream is = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII));
187+
return eval(new FastIn(is));
219188
}
220189

221-
static void assertEq(int exp, int act) {
190+
private static void assertEq(int exp, int act) {
222191
if (exp != act) {
223192
throw new AssertionError("Expected=" + exp + ", actual=" + act);
224193
}

0 commit comments

Comments
 (0)