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

题目说明:

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

题目解析:

运算时由后序式的前方开始读取,遇到运算元先存入堆叠,如果遇到运算子,则由堆叠中取出两个运算元进行对应的运算,然后将结果存回堆叠,如果运算式读取完 毕,那么堆叠顶的值就是答案了,例如我们计算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);
}
时间: 2024-10-04 18:58:53

[经典算法]后序式的运算的相关文章

【后序式的运算】

/* 后序式的运算 说明: 将中序式转换为后序式的好处是,不用处理运算子先后顺序问题,只要依序由运算式由前往后读取即可. 解法: 运算时由后序式的前方开始读取,遇到运算元先存入堆叠,如果遇到运算子,则由堆叠中取出两个运算元进行对应的运算,然后将 结果存回堆叠,如果运算式读取完毕,那么堆叠顶的值就是答案了,例如我们计算12+34+* 这个运算式 (也就 是(1+2)*(3+4) ): 读取 堆叠 1 1 2 12 + 3 3 33 (1+2后存回) 4 334 + 37 (3+4后存回) * 21

[经典算法] 中序式转后序式/前序式

题目说明: 平常所使用的运算式,主要是将运算元放在运算子的两旁,例如a+b/d这样的式子,这称之为中序(Infix)表示式,对于人类来说,这样的式子很容易理 解,但由于电脑执行指令时是有顺序的,遇到中序表示式时,无法直接进行运算,而必须进一步判断运算的先后顺序,所以必须将中序表示式转换为另一种表示方 法.可以将中序表示式转换为后序(Postfix)表示式,后序表示式又称之为逆向波兰表示式(Reverse polish notation),它是由波兰的数学家卢卡谢维奇提出,例如(a+b)*(c+d

后序式的运算

由于作者不习惯该编辑器,只是贴出上本文的截图,详见:https://www.yuque.com/docs/share/c2e4fb51-00e7-405b-b595-596dd2976017 原文地址:http://blog.51cto.com/4754569/2325354

7.5 中序式转后序式

7-6 toPosfix.c 1 #include <stdio.h> 2 #include <stdlib.h> 3 int PRI(char op) //设定算符的优先级 4 { 5 switch (op) 6 { 7 case '+': 8 case '-': 9 return 1; 10 case '*': 11 case '/': 12 return 2; 13 default: 14 return 0; 15 } 16 } 17 char *toPosfix(char

经典算法大全

原文地址:经典算法大全 作者:liurhyme 经                                                                    典                                                                    算                                                                    法                  

java 经典算法(转)

1.河内之塔.. 2.Algorithm Gossip: 费式数列. 3. 巴斯卡三角形 4.Algorithm Gossip: 三色棋 5.Algorithm Gossip: 老鼠走迷官(一) 6.Algorithm Gossip: 老鼠走迷官(二) 7.Algorithm Gossip: 骑士走棋盘 8.Algorithm Gossip: 八皇后 9.Algorithm Gossip: 八枚银币. 10.Algorithm Gossip: 生命游戏. 11.Algorithm Gossip:

java学习-4 经典算法

1.河内之塔.. 2.Algorithm Gossip: 费式数列. 3. 巴斯卡三角形 4.Algorithm Gossip: 三色棋 5.Algorithm Gossip: 老鼠走迷官(一) 6.Algorithm Gossip: 老鼠走迷官(二) 7.Algorithm Gossip: 骑士走棋盘 8.Algorithm Gossip: 八皇后 9.Algorithm Gossip: 八枚银币. 10.Algorithm Gossip: 生命游戏. 11.Algorithm Gossip:

【经典算法大全】收集51种经典算法 初学者必备

<经典算法大全>是一款IOS平台的应用.里面收录了51种常用算法,都是一些基础问题.博主觊觎了好久,可悲哀的是博主没有苹果,所以从网上下了老奔的整理版并且每个都手敲了一遍. 虽然网上也有博客贴了出来,但是自己写写感觉总是好的.现在分享个大家. 代码和运行结果难免有出错的地方,请大家多多包涵. 1.河内之塔(汉诺塔) 2.费式数列 3.巴斯卡三角形 4.三色棋 5.老鼠走迷宫(1) 6.老鼠走迷宫(2) 7.骑士走棋盘 8.八皇后 9.八枚银币 10.生命游戏 11.字串核对 12.双色河内塔,

经典白话算法之二叉树中序前序序列(或后序)求解树

这种题一般有二种形式,共同点是都已知中序序列.如果没有中序序列,是无法唯一确定一棵树的. <1>已知二叉树的前序序列和中序序列,求解树. 1.确定树的根节点.树根是当前树中所有元素在前序遍历中最先出现的元素. 2.求解树的子树.找出根节点在中序遍历中的位置,根左边的所有元素就是左子树,根右边的所有元素就是右子树.若根节点左边或右边为空,则该方向子树为空:若根节点 边和右边都为空,则根节点已经为叶子节点. 3.递归求解树.将左子树和右子树分别看成一棵二叉树,重复1.2.3步,直到所有的节点完成定