본문 바로가기
개발/c++

스택을 이용한 한 자리수 계산기

by p_human 2020. 6. 14.

오랜만에 글을 쓴다.

뭐라도 해야겠다 싶어서 갑자기 떠오른게 있었다. 간단하게라도 계산기를 구현해서 앱으로 출시를 해보면 어떨까해서 시작했다. 일단 집에 '윤성우의 열혈 자료구조'가 있어서 최대한 책을 안보고 이론적인 내용을 생각하면서 코드를 작성했다. (그래도 안되면 책을 보고 해서 거의 책이랑 똑같다)너무 복습을 안해서 까먹긴 했지만 대부분 차근차근 이해가 되었다.

계산기 프로그램(반쪽짜리)을 짜면서 어떻게 하면 여러 자리 수의 계산을 할 수 있을까에 대해서 생각을 해봤다. 하지만 답이 안나왔다. 그래서 일단 한 자리수의 연산만 가능한 계산기에 대해서 코드만 올려본다.

이 코드에 대한 이론적인 부분은 나중에 할 듯 싶다. 지금 하고 싶지만...

 

#include <iostream>
#include <string>
#include <stack>

using namespace std;

typedef enum class OPERATIONLIST {
    NONE = 0,
    PARENTHESIS = 1,
    ADD_SUB = 2,
    MUT_DIV = 3
}OPER;

typedef enum class OPERCOMPARESIZE {
    SMALL = -1,
    EQUALS,
    BIG
}RESULT;

// 연산자들의 우선순위 정하기
OPER GetOpPrec(char oper) {
    switch (oper) {
    case '(':
        return OPER::PARENTHESIS;
    case '+':
    case '-':
        return OPER::ADD_SUB;
    case '*':
    case '/':
        return OPER::MUT_DIV;
    default: // 다른 연산자가 들어왔을 때
        return OPER::NONE;
    }
}

// 연산자를 스택에 넣을 때 비교하는 함수
RESULT CompareOper(char oper1, char oper2) {
    OPER getOper1 = GetOpPrec(oper1);
    OPER getOper2 = GetOpPrec(oper2);
    if (getOper1 > getOper2) // tok > tmp.top()
        return RESULT::BIG;
    else if (getOper1 < getOper2) 
        return RESULT::SMALL;
    else
        return RESULT::EQUALS;
}

// 전달된 exp의 중위 표기법을 후위 표기법으로 변환하는 함수
// 중위 표기법 : 5+3/5
// 후위 표기법 : 535/+
string ConvertToRPN(string exp) {
    int i = 0, ExpIndex = 0;
    char tok;
    stack<int> operStack;
    string newExp = exp;
    while (i < newExp.length()) {
        tok = exp[i];
        if (isdigit(tok)) { // 문자가 숫자인지 확인
            newExp[ExpIndex++] = tok; // 새로운 문자열에 추가
            i++;
            continue;
        }
        switch (tok) {
        case '(':
            // 그냥 넣어도 되지 않을까??
            operStack.push(tok);
            break;
        // '('를 만날 때까지 스택에서 차례대로 꺼내서
        // 새로운 문자배열에 추가시킨다.
        case ')':
            char tmp;
            while (true) {
                tmp = operStack.top();
                operStack.pop();
                if (tmp == '(')
                    break;
                newExp[ExpIndex++] = tmp;
            }
            break;
        case '+':
        case '-':
        case '*':
        case '/':
            while (!operStack.empty() && CompareOper(operStack.top(), tok)
                >= RESULT::EQUALS) {
                newExp[ExpIndex++] = operStack.top();
                operStack.pop();
            }
            operStack.push(tok);
            break;
        }
        i++;
    }
    while (!operStack.empty()) {
        newExp[ExpIndex++] = operStack.top();
        operStack.pop();
    }
    return newExp;
}

int EvalRPNExp(string exp) {
    int i = 0;
    char tok;
    stack<int> numStack;
    while (i < exp.length()) {
        tok = exp[i];
        if (isdigit(tok)) {
            numStack.push(tok - '0');
            i++;
            continue;
        }

        int rNum = numStack.top(); numStack.pop();
        int lNum = numStack.top(); numStack.pop();
        switch (tok) {
        case '+':
            numStack.push(lNum + rNum);
            break;
        case '-':
            numStack.push(lNum - rNum);
            break;
        case '*':
            numStack.push(lNum * rNum);
            break;
        case '/':
            numStack.push(lNum / rNum);
            break;
        }
        i++;
    }
    return numStack.top();
}

int main()
{
    string infixString = "1+2+3/3";
    infixString = ConvertToRPN(infixString);
    cout << EvalRPNExp(infixString);
    return 0;
}

어떻게하면 여러 자리 수를 계산할 수 있을까??

':'로 구분해서 계산하나??

흠... 이걸 해결해야지 안드로이드로 옮겨서 어떻게든 앱으로 출시할텐데...

역시 중-고등학교 때 공부를 안해서 생각하는 과정이 느리고 비효율적이다.

매일 글을 남기고 싶은데 잘 안된다. 오늘부터 다시 도전이다.

'개발 > c++' 카테고리의 다른 글

클래스 멤버함수를 스레드에서 실행  (0) 2019.11.01