#include "iostream.h"
#include "iomanip.h"
#include "ctype.h"
#include "string.h"
#include "stdlib.h"
/*
차례로 스택에 5 4 1이란 값을 저장하면
|-------|
|-------|
|-------|
|-------|
|-------|
-> top = -1 스택이 비어있는 상태입니다.
|-------|
|-------|
|-------|
|-------|
| 5 | -> top
|-------|
|-------|
|-------|
|-------|
| 4 | -> top
|-------|
| 5 |
|-------|
|-------|
|-------|
| 1 | -> top
|-------|
| 4 |
|-------|
| 5 |
|-------|
push()소스를 보시면 아시겠지만 stack[++top]
이렇게 해주는것은 초기화가 -1로 되어있기 때문에
stack[0]번지부터 값을 넣어주기 위한 것이지요.
여기서 자료를 꺼내게 (pop)하게 되면 소스와 마찬가지로
stack[top--]입니다.
|-------|
|-------|
|-------|
| 4 | -> top
|-------|
| 5 |
|-------|
1이란 자료를 꺼내고 top은 한칸 아래로 내려가게 됩니다.
마지막 5의 값까지 꺼내게 되면 top 은 -1이 되겠지요.
이것이 스택입니다. 그리고 왜 스택을 이용해 계산기를
만들어야 하냐면요..우선 컴퓨터가 연산을 할때
우리가 5+3*5 라는 산술식을 입력하게 되면
컴퓨터는 연산자를 중심으로 앞뒤의 숫자를 계산하게 됩니다.
그런데 연산자에는 우선순위가 있지요? 그리고 괄호도 있습니다.
그렇기 때문에 우선 산술식을 후위연산자로 바꿔줘야 하는데요
535*+입니다. 바꾸는 법은 이산수학하셨으면 아실꺼예여.
이렇게 후위연산자로 바꾼 식에서 숫자들은 모두 스택에 집어넣구여
연산자가 나오면 스택에서 하나씩 출력하여 계산하면 됩니다.
스택에 5 3 5가 있고 첫번재 *연산자가 나옵니다. 5와 3을 꺼내어 *
을 하고 계산된 결과를 스택에 집어넣으면 5 15가 되겠지요?
그다음 +연산자가 나옵니다. 15와 5 를 꺼내어 계산을 하면 우선순위
에 맞게 계산이 되어집니다. 이 부분을 이해하지 못하신다면 아래
소스도 이해가 안가실 꺼예여. 여러 산술식을 후위연산자로 바꾸고
스택에 집어넣었다가 꺼내면서 계산을 해보세요.
이제 소스설명으로 넘어가겠습니다.
*/
const int StackSize=10;
class CharStack {
private:
int stack[StackSize];
int top;
public:
CharStack() { top = -1; }
void push(char val) { stack[++top] = val; }
char pop() { return stack[top--]; }
int isEmpty() { return top == -1; } // top이 -1이면 스택이 비어있는 것이지요
int isFull() { return top == StackSize-1; } // 이것역시 top이 9의 값을 가지면
//더이상 자료를 넣을수 없습니다.
void init() { top = -1; } // 스택을 초기화 시키는 것입니다.
char getTop() { return stack[top]; } // 현재 스택의 자료를 가져옵니다.
}; //이것이 일반적인 스택의 구조입니다.
//char를 위한 스택
class IntStack {
private:
int stack[StackSize];
int top;
public:
IntStack() { top = -1; }
void push(int val) { stack[++top] = val; }
int pop() { return stack[top--]; }
int isEmpty() { return top == -1; }
int isFull() { return top == StackSize-1; }
}; //위와 같은구조로 정수를 담기위한 스택입니다.
//우선 메인으로 내려가세요
class Calculator {
private:
char buffer[80];
char postfix[80];
IntStack s1;
CharStack s2;
void result();
int priority(char);
public:
void calculate(char[]);
};
int Calculator::priority(char ch)
{
if(ch == '*' || ch == '/')
return 3;
else if(ch == '+' || ch == '-')
return 2;
else
return 1;
}//우선순위에 따라 리턴값을 줍니다.
void Calculator::calculate(char temp[])
{
strcpy(buffer, temp); //전달받은 문자열을 buffer에 복사합니다.
//strcpy(복사될 변수의 주소, 복사할 변수의 주소);
int i = 0, j = 0;
char ch;
while (buffer[i] != '\0') { // 문자열이 끝날때까지 실행됩니다.
if (buffer[i] == ' ')
i++; //공백을 제거하고
else if (isdigit(buffer[i])) { //숫자라면
while (isdigit(buffer[i])) //숫자인동안
postfix[j++] = buffer[i++]; //postfix배열에 저장합니다.
postfix[j++] = ' '; //그리고 공백을 넣어 숫자와 숫자사이를 구분합니다.
}
else if (buffer[i] == '(') { //여는 괄호가 나오면 스택에 저장합니다.
s2.push(buffer[i]);
i++;
}
else if (buffer[i] == ')') { //닫는 괄호가 나오면
ch = s2.pop(); //스택에서 pop을 하여
while (ch != '(') { //여는 괄호가 아니라면
postfix[j++] = ch; //postfix에 저장하고
postfix[j++] = ' '; //연산자를 구분하기 위해 공백을 입력합니다.
ch = s2.pop(); //여는 괄호가 나오면 반복문을 빠져나가고
//여는 괄호는 그냥 없어집니다.
//어차피 후위표기식은 괄호가 없기때문에..
}
i++;
}
else { //연산자가 나올경우
if (s2.isEmpty()) //스택이 비어있으면
s2.push(buffer[i++]); //무조건 집어넣고
else { //스택이 비어있지 않은경우
while (!s2.isEmpty() && priority(s2.getTop()) >= priority(buffer[i])) {
//스택이 비어있지 않고 스택의 맨위의 문자가 현재 문자보다 우선순위가 높거나
//같으면 (priority함수로 올라가 봅니다.)
ch = s2.pop();
//스택의 연산자를 pop하여
postfix[j++] = ch; //postfix에 저장합니다.
postfix[j++] = ' '; //그리고 공백을 이용하여 구분
}
s2.push(buffer[i]); //그리고 현재 연산자를 집어넣습니다.
//우선순위에 의해 현재 연산자는 맨 위에 올라가게 하는거지요
i++;
}
}
}
while (!s2.isEmpty()) { //그리고 스택이 비어있지 않은경우
ch = s2.pop(); //남아있는 연산자를 pop하여
postfix[j++] = ch; //postfix배열에 저장하고
postfix[j++] = ' '; //공백을 이용하여 구분합니다.
}
postfix[j] = '\0'; //마지막에 널값을 넣어주어 문자열을 완성합니다.
result(); //여기까지 postfix 후위연산식이 완성되었고, result함수를 호출합니다.
}
void Calculator::result()
{
int i = 0, k;
char token[5];
int num, number, num1, num2;
char ch;
while (postfix[i] != '\0') { //위에서 만들어놓은 후위연산식이 끝날때까지 반복
if (isdigit(postfix[i])) { //숫자라면
k = 0;
while (isdigit(postfix[i])) //숫자인동안
token[k++] = postfix[i++]; //token에 저장합니다.
token[k] = '\0'; //마지막에 널값을 넣어 문자열을 완성하고
num = atoi(token); //atoi를 이용해 정수로 변환하여
s1.push(num); //정수형 스택에 저장합니다.
}
else if (postfix[i] == ' ') //공백을 건너뛰어
i++;
else { //연산자가 나오면
ch = postfix[i++];
num1 = s1.pop(); //우선 스택의 숫자 두개를
num2 = s1.pop(); //pop하고
if (ch == '+') //연산자에 맞는 계산을 하여
number = num2 + num1;
else if (ch == '-')
number = num2 - num1;
else if (ch == '*')
number = num2 * num1;
else if (ch == '/')
number = num2 / num1;
s1.push(number); //다시 계산된 값을 스택에 저장합니다.
}
i++;
}
cout << "result" << setw(10) << ":" << s1.pop() << endl;
} //결과가 나오겠지요?
void main()
{
char temp[80];
cout.setf(ios::left); //출력할때 정렬을 위한 문장입니다.
Calculator myCalc1; //클래스의 객체를 생성하구여
while (cin.getline(temp, 80)) //사용자에게 한줄을 입력받고
myCalc1.calculate(temp); //입력받은 것을 calculate함수에 호출합니다.
} //->calculate함수로 올라가세요
//괄호 들어가는 수식와 2+3*5같은
//수식에 우선순위 계산 모두 됩니다.
'IT_Programming > C · C++' 카테고리의 다른 글
포인터 선언과 연산 테스트 (0) | 2007.01.24 |
---|---|
입력받은 수가 소수인지 아닌지를 알아보자 (0) | 2007.01.23 |
입력 받은 두 수의 최대 공약수를 구하는 소스 (0) | 2007.01.19 |
문자열을 이용한 산술 연산 (2의 지수승 더하기) (0) | 2006.03.06 |
malloc을 사용하여 동적으로 배열을 받고 처리하는 예 (0) | 2006.01.31 |