[经典算法]后序式的运算

题目说明:

通过将中序式转换为后序式,不用处理运算子先后顺序问题,只要依序由运算式由前往后读取即可。

 

题目解析:

运算时由后序式的前方开始读取,遇到运算元先存入堆叠,如果遇到运算子,则由堆叠中取出两个运算元进行对应的运算,然后将结果存回堆叠,如果运算式读取完 毕,那么堆叠顶的值就是答案了,例如我们计算12+34+*这个运算式(也就是(1+2)*(3+4)):

读取

堆叠

1

1

2

1 2

+

3 // 1+2 后存回

3

3 3

4

3 3 4

+

3 7 // 3+4 后存回

*

21 // 3 * 7 后存回

 

程序代码:

#include <gtest/gtest.h>

using namespace std;

int GetOperatorPrior(char value)
{
    int nResult = 0;
    switch(value)
    {
    case '+':
    case '-':
        {
            nResult = 1;
        }
        break;

    case '*':
    case '/':
        {
            nResult = 2;
        }
        break;
    }

    return nResult;
}

bool ConvertToPostfix(const string& infixExp, string& postfixExp)
{
    postfixExp.clear();
    int* pStack = new int[infixExp.size()];
    int nTop = -1;

    for (string::size_type i=0; i < infixExp.size(); i++)
    {
        char cValue = infixExp[i];
        switch (cValue)
        {
        case '(':
            {
                pStack[++nTop] = cValue;
            }
            break;

        case ')':
            {
                while ( (nTop >= 0) && pStack[nTop] != '(')
                {
                    postfixExp += pStack[nTop];
                    --nTop;
                }
                // not find '(', express is invalid.
                if (nTop < 0)
                {
                    return false;
                }

                --nTop;
            }
            break;

        case '+':
        case '-':
        case '*':
        case '/':
            {
                while ( (nTop >= 0) &&
                    GetOperatorPrior(pStack[nTop]) >= GetOperatorPrior(cValue))
                {
                    postfixExp += pStack[nTop];
                    --nTop;
                }

                pStack[++nTop] = cValue;
            }
            break;

        default:
            postfixExp += cValue;
            break;
        }
    }

    while (nTop >= 0)
    {
        postfixExp += pStack[nTop--];
    }

    return true;
}

bool CalcValue(double v1, double v2, double& value, char express)
{    
    bool bResult = true;
    switch (express)
    {
    case '+':
        value = v1 + v2;        
        break;

    case '-':
        value = v1 - v2;
        break;

    case '*':
        value = v1 * v2;
        break;

    case '/':
        if (fabs(v2) < 1e-15)
        {
            return false;
        }

        value = v1 / v2;
        break;

    default:
        bResult = false;
        break;
    }

    return bResult;
}

bool ExpressCalc(const string& express, double& value)
{
    string PostfixExpress;
    if (!ConvertToPostfix(express, PostfixExpress))
    {
        return false;
    }

    double* OperandStack = new double[PostfixExpress.size()];
    int nTop = -1;

    for (string::size_type i = 0; i < PostfixExpress.size(); ++i)
    {
        char cValue = PostfixExpress[i];
        switch (cValue)
        {
        case '+':            
        case '-':
        case '*':
        case '/':
            {
                // Operand not enough
                if (nTop < 1)
                {
                    return false;
                }

                double dResult;
                if (!CalcValue(OperandStack[nTop-1], OperandStack[nTop], dResult, cValue))
                {
                    return false;
                }

                OperandStack[nTop-1] = dResult;
                --nTop;
            }
            break;

        default:
            if (cValue < '0' && cValue > '9')
            {
                return false;    
            }
            OperandStack[++nTop] = cValue - '0';

            break;
        }
    }

    if (nTop >= 1)
    {
        return false;
    }

    value = OperandStack[0];

    return true;
}

TEST(Algo, tExpressCalc)
{
    //
    //    Postfix Convert
    //

    // a+b*d+c/d => abd*+cd/+
    string strResult;
    ConvertToPostfix("a+b*d+c/d",strResult);
    ASSERT_EQ("abd*+cd/+",strResult);

    // (a+b)*c/d+e => ab+c*d/e+
    ConvertToPostfix("(a+b)*c/d+e",strResult);
    ASSERT_EQ("ab+c*d/e+",strResult);

    // ((a)+b*(c-d)+e/f)*g => abcd-*+ef/g*
    ConvertToPostfix("((a)+b*(c-d)+e/f)*g",strResult);
    ASSERT_EQ("abcd-*+ef/+g*",strResult);

    // 1+3*4+2/5 => 13.4
    double dResult = 0.0;
    ExpressCalc("1+3*4+2/5",dResult);
    ASSERT_DOUBLE_EQ(13.4,dResult);

    // (4+6)*1/9+7 => 8.1111111111111111111111111111111
    ExpressCalc("(4+6)*1/9+7",dResult);
    ASSERT_DOUBLE_EQ(8.1111111111111111111111111111111,dResult);

    // ((5)+2*(1-7)+3/8)*4 => -26.5
    ExpressCalc("((5)+2*(1-7)+3/8)*4",dResult);
    ASSERT_DOUBLE_EQ(-26.5,dResult);
}
posted @ 2015-09-22 16:31  Quincy  阅读(547)  评论(0编辑  收藏  举报