[C++] BOJ #1935 후위 표기식2
Posted on 2022. 01. 31
문제
후위 표기식과 각 피연산자에 대응하는 값들이 주어져 있을 때, 그 식을 계산하는 프로그램을 작성하시오.
입력
첫째 줄에 피연산자의 개수(1 ≤ N ≤ 26) 가 주어진다. 그리고 둘째 줄에는 후위 표기식이 주어진다. (여기서 피연산자는 A~Z의 영대문자이며, A부터 순서대로 N개의 영대문자만이 사용되며, 길이는 100을 넘지 않는다) 그리고 셋째 줄부터 N+2번째 줄까지는 각 피연산자에 대응하는 값이 주어진다. 3번째 줄에는 A에 해당하는 값, 4번째 줄에는 B에 해당하는 값, 5번째 줄에는 C ...이 주어진다, 그리고 피연산자에 대응하는 값은 100보다 작거나 같은 자연수이다.
후위 표기식을 앞에서부터 계산했을 때, 식의 결과와 중간 결과가 -20억보다 크거나 같고, 20억보다 작거나 같은 입력만 주어진다.
출력
- 계산 결과를 소숫점 둘째 자리까지 출력한다.
1. 아이디어 및 실수
- 아이디어:
- 스택을 활용하여 대문자가 나오면 수를 쌓고, 연산자가 나오면 스택에서 가장 위의 두 수를
pop
해주어 해당 연산 진행 후 다시push
하는 방식 - 후위 표기식에 대문자와 연산자가 섞여나오는데, 이는 ASCII 코드를 활용하여 구분한다.
- 스택을 활용하여 대문자가 나오면 수를 쌓고, 연산자가 나오면 스택에서 가장 위의 두 수를
- 실수: 아이디어의 방향성은 맞았지만, 역시 사소하게 놓친 부분이 있었다.
- 출력조건의 소숫점 둘째자리까지 출력을 못봤다. (따라서, 정답부분을 그냥
%f
로 출력했었는데 나중에%.2f
로 수정해줌) AA+A+
와 같이 총 피연산자의 개수(1)와 알파벳의 등장 횟수(3)가 맞지 않는 경우를 고려하지 않았었다. 그래서 알파벳이 나올때마다 피연산자가 저장된 배열에서 index를 증가시키며 하나씩 스택에push
해주었었다.
(아래 코드의 operIdx가 index 역할)
- 출력조건의 소숫점 둘째자리까지 출력을 못봤다. (따라서, 정답부분을 그냥
#include <iostream>
#include <stack>
#include <cstring>
using namespace std;
int main()
{
//operands: 피연산자들(숫자)을 저장하는 배열
//formula: 후위표기식을 저장하는 배열
//a, b: 스택에서 계산할 두 개의 피연산자
//operIdx: operands 배열을 탐색할 인덱스 변수
int N;
double a, b;
int operIdx = 0;
double operands[26];
char formula[100];
stack<double> cal;
//N, 후위표기식, 피연산자들을 입력받는다.
scanf("%d", &N);
scanf("%s", formula);
for (int i = 0; i < N; i++)
{
scanf("%lf", &operands[i]);
}
//후위 표기식에서 알파벳과 연산자를 구분하여 숫자들을 스택에 쌓고, 계산하여 넣는다.
for (int i = 0; i < strlen(formula); i++)
{
//표기식에서 현재 위치가 알파벳을 가리킨다면, 스택에 피연산자(숫자)를 쌓는다.
if (formula[i] >= 65 && formula[i] <= 90)
cal.push(operands[operIdx++]);
//표기식에서 현재 위치가 연산자를 가리킨다면, 스택에 쌓인 두 숫자를 꺼내 연산하고 다시 push한다.
else if (formula[i] == '+')
{
...
}
else if (formula[i] == '-')
{
...
}
else if (formula[i] == '*')
{
...
}
else if (formula[i] == '/')
{
...
}
}
printf("%f\n", cal.top());
}
2. 최종 소스코드 및 해결방법
- 해결방법:
- 대문자 알파벳의 ASCII 코드와 피연산자 배열의 인덱스를 연결시켜주었다. 그러면 해당 알파벳에 대응하는 피연산자가 생기는 셈이다. 예를 들어, A의 ASCII 코드는 65이므로, A에 대응하는 피연산자를 얻으려면 피연산자 배열에서
(int)A - 65
를 하면 된다. 마찬가지로, 다른 대문자들도int로 변환시킨 해당 대문자의 ASCII코드 - 65
를 하면 대응하는 피연산자를 얻을 수 있다. 최종 소스코드는 아래와 같다.
- 대문자 알파벳의 ASCII 코드와 피연산자 배열의 인덱스를 연결시켜주었다. 그러면 해당 알파벳에 대응하는 피연산자가 생기는 셈이다. 예를 들어, A의 ASCII 코드는 65이므로, A에 대응하는 피연산자를 얻으려면 피연산자 배열에서
#include <iostream>
#include <stack>
#include <cstring>
using namespace std;
int main()
{
//operands: 피연산자들(숫자)을 저장하는 배열
//formula: 후위표기식을 저장하는 배열
//a, b: 스택에서 계산할 두 개의 피연산자
int N;
double a, b;
double operands[26];
char formula[100];
stack<double> cal;
//N, 후위표기식, 피연산자들을 입력받는다.
scanf("%d", &N);
scanf("%s", formula);
for (int i = 0; i < N; i++)
{
scanf("%lf", &operands[i]);
}
//후위 표기식에서 알파벳과 연산자를 구분하여 숫자들을 스택에 쌓고, 계산하여 넣는다.
for (int i = 0; i < strlen(formula); i++)
{
//표기식에서 현재 위치가 알파벳을 가리킨다면, 스택에 피연산자(숫자)를 쌓는다.
if (formula[i] >= 65 && formula[i] <= 90)
{
int index = (int)formula[i] - 65;
cal.push(operands[index]);
}
//표기식에서 현재 위치가 연산자를 가리킨다면, 스택에 쌓인 두 숫자를 꺼내 연산하고 다시 push한다.
else if (formula[i] == '+')
{
a = cal.top();
cal.pop();
b = cal.top();
cal.pop();
cal.push(b + a);
}
else if (formula[i] == '-')
{
a = cal.top();
cal.pop();
b = cal.top();
cal.pop();
cal.push(b - a);
}
else if (formula[i] == '*')
{
a = cal.top();
cal.pop();
b = cal.top();
cal.pop();
cal.push(b * a);
}
else if (formula[i] == '/')
{
a = cal.top();
cal.pop();
b = cal.top();
cal.pop();
cal.push(b / a);
}
}
printf("%.2f\n", cal.top());
}