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

题目说明:

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

 

题目解析:

用手算的方式来计算后序式相当的简单,将运算子两旁的运算元依先后顺序全括号起来,然后将所有的右括号取代为左边最接近的运算子(从最内层括号开始),最后去掉所有的左括号就可以完成后序表示式,例如:

a+b*d+c/d   =>    ((a+(b*d))+(c/d)) -> bd*+cd/+

如果要用程式来进行中序转后序,则必须使用堆叠,演算法很简单,直接叙述的话就是使用回圈,取出中序式的字元,遇运算元直接输出,堆叠运算子与左括号, ISP>ICP的话直接输出堆叠中的运算子,遇右括号输出堆叠中的运算子至左括号。

以下是虚拟码的运算法,\0表示中序式读取完毕:

Procedure Postfix(infix) [
    Loop [
        op = infix(i) 
        case [
            :x = '\0': 
                while (stack not empty) 
                     // output all elements in stack 
                end 
                return 
             :x = '(': 
                 // put it into stack 
             :x is operator: 
                  while (priority(stack[top]) >= 
                         priority(op)) [
                       // out a element from stack 
                  ]
                  // save op into stack 
             :x = ')': 
                   while ( stack(top) != '(' ) [
                       // out a element from stack 
                   ]
                   top = top - 1  // not out '( 
             :else: 
                   // output current op 
        ]
        i++; 
    ]
]

 

例如(a+b)*(c+d)这个式子,依演算法的输出过程如下:

OP

STACK

OUTPUT

(

(

-

a

(

a

+

(+

a

b

(+

ab

)

-

ab+

*

*

ab+

(

*(

ab+

c

*(

ab+c

+

*(+

ab+c

d

*(+

ab+cd

)

*

ab+cd+

-

-

ab+cd+*

如果要将中序式转为前序式,则在读取中序式时是由后往前读取,而左右括号的处理方式相反,其余不变,但输出之前必须先置入堆叠,待转换完成后再将堆叠中的 值由上往下读出,如此就是前序表示式。

 

程序代码:

#include <iostream>
#include <stack>
#include <algorithm>
#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();
    stack<int> Operators;
    for (string::size_type i = 0; i < infixExp.size(); ++i)
    {
        char cValue = infixExp[i];
        switch(cValue)
        {
        case '(':
            {
                Operators.push(cValue);
            }
            break;

        case ')':
            {
                while(!Operators.empty() && 
                    (Operators.top() != '('))
                {
                    postfixExp += Operators.top();
                    Operators.pop();
                }

                Operators.pop();
            }
            break;

        case '+':
        case '-':
        case '*':
        case '/':
            {
                while (!Operators.empty() && 
                    (GetOperatorPrior(Operators.top()) >= GetOperatorPrior(cValue)) )
                {
                    postfixExp += Operators.top();
                    Operators.pop();
                }

                Operators.push(cValue);
            }
            break;

        default:
            postfixExp += cValue;
            break;
        }
    }

    while(!Operators.empty())
    {
        postfixExp += Operators.top();
        Operators.pop();
    }

    return true;
}

bool ConvertToPrefix(const string& infixExp, string& prefixExp)
{
    prefixExp.clear();
    int* Stack = new int[infixExp.size()+1];
    int  nTop = 0;

    for (int i = infixExp.size() - 1; i >= 0; --i)
    {
        char cValue = infixExp[i];
        switch (cValue)
        {
        case ')':
            {                
                Stack[++nTop] = ')';                
            }
            break;

        case '(':
            {
                while (nTop &&
                    Stack[nTop] != ')')
                {
                    prefixExp += Stack[nTop];
                    nTop--;
                }

                nTop--;
            }
            break;

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

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

        default:
            prefixExp += cValue;
            break;
        }
    }

    while (nTop)
    {
        prefixExp += Stack[nTop--];
    }

    reverse(prefixExp.begin(), prefixExp.end());

    return true;
}

TEST(Algo, tInFixPostfix)
{
    //
    //    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);

    //
    //    Prefix Convert
    //

    // a+b*d+c/d => +a+*bd/cd
    ConvertToPrefix("a+b*d+c/d",strResult);
    ASSERT_EQ("+a+*bd/cd",strResult);

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

    // ((a)+b*(c-d)+e/f)*g => *+a+*b-cd/efg
    ConvertToPrefix("((a)+b*(c-d)+e/f)*g",strResult);
    ASSERT_EQ("*+a+*b-cd/efg",strResult);

}
posted @ 2015-09-22 14:29  Quincy  阅读(1203)  评论(0编辑  收藏  举报