C# 프로그래밍 기초 실습 전자책

C# / .NET 알고리즘과 퀴즈
본 알고리즘 퀴즈 문제는 C#/.NET 개발자를 위한 알고리즘 인터뷰 혹은 C# 프로그래밍을 통한
문제 해결 알고리즘을 연구해 보는데 도움이 되고자 작성되었습니다.


퀴즈 질문


예상답변/설명

식은 숫자와 사칙연산 부호로 구성되어 있다. 먼저 Infix 방식으로 된 식을 PostFix 방식으로 변경하는데, 이는 부호의 우선순위에 따라 식을 변형하기 위한 것이다( O(n) ). PostFix로 변경된 식을 읽어 숫자인 경우는 스택에 집어 넣고, 연산자가 나타나면 스택에서 상위 2개의 값을 꺼내와서 해당 연산에 사용한다. 이 경우 먼저 꺼낸 것은 b에 나중에 꺼낸 것은 a에 두고 a-b와 같이 피연산자로 사용한다. 연산의 결과는 다시 스택에 넣고, 다음 식을 읽어 반복적으로 처리한다. 이렇게 모든 연산이 끝나면, 맨 마지막에는 스택에 결과값만 저장되므로 이를 꺼내서 리턴하면 된다.

public static void RunTest()
{
    string expr = "11 + 22 * 33 - 44";
    int result = Evaluate(expr);
    Console.WriteLine(result);
}

// 제약: 4칙연산만
static int Evaluate(string expression)
{                        
    // Convert to Postfix
    string postFix = ConvertToPostfix(expression);
    Console.WriteLine(postFix);

    // Evaluate Postfix
    return EvaluatePostfix(postFix);
}

static string ConvertToPostfix(string expr)
{            
    Stack<char> stack = new Stack<char>();
    StringBuilder sb = new StringBuilder();

    foreach (var ch in expr)
    {
        if (ch >= '0' && ch <= '9' || ch == ' ')
        {
            sb.Append(ch);
        }
        else if (ch == '*' || ch == '/')
        {                    
            stack.Push(ch);
        }
        else if (ch == '+' || ch == '-')
        {
            while (stack.Count > 0)
            {
                sb.Append(stack.Pop());
                sb.Append(' ');
            }
            stack.Push(ch);
        }
        else
        {
            throw new ArgumentException();
        }
    }

    if (stack.Count > 0)
    {
        sb.Append(stack.Pop());
    }

    return sb.ToString();
}

static int EvaluatePostfix(string expr)
{
    Stack<int> stack = new Stack<int>();
    int c = 0;

    for(int i=0; i<expr.Length; i++)
    {
        char ch = expr[i];

        if (ch == ' ') continue;
                
        if (ch >= '0' && ch <= '9')
        {
            string s = "";
            while (i<expr.Length && expr[i] >= '0' && expr[i] <= '9')
            {
                s += expr[i++];
            }
            i--;                    
            stack.Push(int.Parse(s));
        }
        else if (ch == '+' || ch == '-' || ch == '*' || ch == '/')
        {
            int b = stack.Pop();
            int a = stack.Pop();
            switch (ch)
            {
                case '+': c = a + b; break;
                case '-': c = a - b; break;
                case '*': c = a * b; break;
                case '/': c = a / b; break;
            }
            stack.Push(c);                    
        }
        else
        {
            throw new ArgumentException();
        }
    }

    return stack.Pop();
}