1단계 : 수식의 각 연산자에 대해서 우선순위에 따라 괄호를 사용하여 표현한다.
((A*B) - (C/D))
2단계 : 각 연산자를 그에 대응하는 오른쪽 괄호 뒤로 이동시킨다.
((A B)* (C D)/)-
3단계 : 괄호를 제거한다.
AB*CD/-
→ 복잡하고, 해당 방식을 구현하는데 어려움이 있을 수 있다.
)
이면, 스택 top에 (
가 올 때까지 pop. 왼쪽 괄호만 만나면 pop하고 출력하지 않는다.<예시>
(6 + 5 * (2 - 8) / 2)
pop을 해준다는 것은, 그냥 출력한다는 것으로 이해하면 된다.
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
public class Stack_계산기 {
public static void main(String[] args) {
String expression = "(6+5*(2-8)/2)";
System.out.println(infixToPostfix(expression));
}
static Map<Character, Integer> map = new HashMap<>();
// 프로그램 실행 단계에서 바로 생성이 되기 때문에, 우선 순위가 높아진다.
// 중복해서 만들지 않아도 된다.
static {
map.put('+', 1);
map.put('-', 1);
map.put('*', 2);
map.put('/', 2);
}
// 중위 표기식을 후위 표기식으로 바꾸는
static String infixToPostfix(String infix) {
String postfix = "";
Stack<Character> stack = new Stack<>();
for (int i = 0; i < infix.length(); i++) {
// 숫자가 2개 이상 함께 겹쳐진다면, 다른 방식을 써야 한다.
char c = infix.charAt(i);
// 피연산자가 나오는 경우, 바로 출력
if( c >= '0' && c <= '9' ) {
postfix += c;
}
// 괄호 연산자 처리
else if ( c == '(') {
stack.push(c);
} else if ( c == ')') {
while(stack.peek() != '(') {
char popItem = stack.pop();
postfix += popItem;
}
stack.pop();
}
// 괄호가 아닌 연산자 처리
else {
//연산자 우선순위가 낮은 게 올 때까지 pop
// 여는 괄호의 조건은 뺀다.
while(!stack.isEmpty() && stack.peek() != '('&& map.get(stack.peek()) >= map.get(c)) {
char popItem = stack.pop();
postfix += popItem;
}
stack.push(c);
}
}
// 스택 비워주기
while (!stack.isEmpty()) {
postfix += stack.pop();
}
return postfix;
}
}
static int evalPostfix(String postfix) {
Stack<Integer> stack = new Stack<>();
for(int i = 0; i < postfix.length(); i++) {
char c = postfix.charAt(i);
if( c >= '0' && c <= '9') {
stack.push( c - '0' );
} else {
int num2 = stack.pop(); // 처음 pop은 위에 있는 값이 뽑히게 되므로
int num1 = stack.pop();
int result = 0;
if (c == '+') {
result = num1 + num2;
} else if ( c == '-') {
result = num1 - num2;
} else if ( c == '*') {
result = num1 * num2;
} else if ( c == '/') {
result = num1 / num2;
}
stack.push(result);
}
}
return stack.pop();
}
static int evaluate(String expression) {
String postfix = infixToPostfix(expression);
return evalPostfix(postfix);
}
만약 두 개의 메서드가 하나로 정의되는 경우, 위와 같이 작성하면 돌아가면서 한 번에 진행이 된다.