zoukankan      html  css  js  c++  java
  • [经典算法] 中序式转后序式/前序式

    题目说明:

    平常所使用的运算式,主要是将运算元放在运算子的两旁,例如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的话直接输出堆叠中的运算子,遇右括号输出堆叠中的运算子至左括号。

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

    Procedure Postfix(infix) [
        Loop [
            op = infix(i) 
            case [
                :x = '': 
                    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);
    
    }
  • 相关阅读:
    Vue.js 转自http://zhuanlan.zhihu.com/evanyou/20302927
    Linux 下的终端
    图像热点(图像地图)
    网页多媒体 flash
    下拉列表
    <input> type 属性
    <form>表单
    表格结构
    简介
    <meta>标记
  • 原文地址:https://www.cnblogs.com/Quincy/p/4828862.html
Copyright © 2011-2022 走看看