문제
https://www.acmicpc.net/problem/1918
1918번: 후위 표기식
첫째 줄에 중위 표기식이 주어진다. 단 이 수식의 피연산자는 알파벳 대문자로 이루어지며 수식에서 한 번씩만 등장한다. 그리고 -A+B와 같이 -가 가장 앞에 오거나 AB와 같이 *가 생략되는 등의
www.acmicpc.net
풀이 방법
일반적으로 사용하는 중위 표기식을 컴퓨터가 계산하기 쉬운 후위 표기식으로 바꿔주는 문제다.
중위 표기식을 왼쪽부터 오른쪽 끝까지 훑으며 다음을 연산한다.
- 피연산자면 결과 문자열에 더한다.
(
이면 스택에push
한다.*
와/
이면 스택이 비어있거나 스택의top
이 우선순위가 낮은 기호가 나올 때까지pop
하며 결과 문자열에 더한다.+
와-
이면 스택이 비어있거나 스택의top
이 (가 나올 때까지pop
하며 결과 문자열에 더한다. 연산 우선순위가 제일 낮기 때문이다.)
이면 스택의top
이(
가 나올 때까지pop
하며 결과 문자열에 더한다. 이때 스택의top
인(
도 마저pop
해준다.
이 과정이 끝난 뒤에도 스택이 비어있지 않으면 남은 연산자들을 pop
하며 결과 문자열에 더한다.
최종적으로 결과 문자열을 출력한다.
코드
#include <cstdio>
#include <stack>
#include <string>
#include <cctype>
using namespace std;
int main()
{
char s[101];
scanf("%s", &s);
stack<char> op;
string str(s);
string result = ""; // 결과 문자열
for(int i=0; i<str.size(); i++)
{
if(isalpha(str[i])) result += str[i]; // 1
else
{
if(str[i] == '(') op.push('('); // 2
else if(str[i] == '*' || str[i] == '/') // 3
{
while(!op.empty() && (op.top() == '*' || op.top() == '/'))
{
result += op.top();
op.pop();
}
op.push(str[i]);
}
else if(str[i] == '+' || str[i] == '-') // 4
{
while(!op.empty() && op.top() != '(')
{
result += op.top();
op.pop();
}
op.push(str[i]);
}
else if(str[i] == ')') // 5
{
while(!op.empty() && op.top() != '(')
{
result += op.top();
op.pop();
}
op.pop();
}
}
}
while(!op.empty()) // 6
{
result += op.top();
op.pop();
}
printf("%s", result.c_str()); // 7
return 0;
}
고찰
풀이 자체는 스택을 사용해서 푼다는 것을 알아도 경우에 따라 처리해주는 게 꽤 어렵다.
글 앞서 말했듯이 컴퓨터는 중위 표기식보다 후위 표기 식이 계산하기 더 쉽다. 왜 그럴까?
컴퓨터는 순차적으로 처리하기 때문에 괄호, 연산자, 피연산자가 뒤섞여있는 중위 표기식을 봤을 때, 어떤 것을 먼저 계산해야 할지 알기 어렵기 때문이다.
반면 후위 표기식은 애초에 우선순위대로 되어있기 때문에, 순차적으로 계산하면 된다.
컴퓨터가 후위 표기식을 연산할 때는 다음과 같이 하면 된다.
- 피연산자면 스택에
push
한다. - 연산자면 스택에서 두 번
pop
하여 두 데이터로 연산한 다음 결과를 스택에 다시push
한다. 이때 만약 연산이a + b
라고 하면b
가 스택의top
,a
는 그 아래 데이터다.
계산이 엄청 간단해졌다!
후위표기식 계산과 관련된 문제는 다음과 같다.
https://www.acmicpc.net/problem/1935
1935번: 후위 표기식2
첫째 줄에 피연산자의 개수(1 ≤ N ≤ 26) 가 주어진다. 그리고 둘째 줄에는 후위 표기식이 주어진다. (여기서 피연산자는 A~Z의 영대문자이며, A부터 순서대로 N개의 영대문자만이 사용되며, 길이
www.acmicpc.net