中綴表達式轉換為前綴表達式


中綴表達式轉換為前綴表達式

         在《前綴表達式的計算》中,我們討論了對前綴表達式如何計算:設置一個操作數棧,對前綴表達式從右到左掃描,遇到操作數直接入棧,遇到操作符則從操作數棧彈棧,先彈left值后彈right值,根據操作符進行相應的計算,並將計算結果壓入到操作數棧中,最終將整個前綴表達式掃面完畢。這時操作數棧中只有一個元素,該元素的值即為前綴表達式的值。

         在《中綴表達式轉換為后綴表達式》中,我們討論了如何將一個中綴表達式轉換為其對應的后綴表達式。其思想為:設置一個操作符棧,如果遇到操作數,則直接將操作數放進后綴表達式中,如果遇到非操作數,則:如果是左括號,則將左括號入棧;如果是右括號,則從操作符棧中將操作符彈棧,放入后綴表達式中,直至棧空或遇到棧中的左括號,並將左括號彈棧;如果是其他操作符,則比較其優先級與棧中操作符優先級情況,如果棧中的操作符的優先級大於等於當前操作符,則將棧中操作符彈棧,直至棧空,或棧中操作符優先級小於當前操作符的優先級,將當前操作符壓棧。當從左到右順序掃描完整個中綴表達式后,檢測操作符棧,如果非空,則依次彈棧,將彈出的操作符依次壓入到后綴表達式中。最終,得到中綴表達式對應的后綴表達式。如果還想計算后綴表達式的值,則可以參考《后綴表達式的計算》。

         本文我們是討論如何將中綴表達式轉換為前綴表達式。

         我們先給出中綴表達式轉換前綴表達式的程序,然后再對程序進行相關講解,之后在與中綴表達式轉換后綴表達式的過程進行比較,分析其中的差異存在於哪里。

// 中綴表達式轉換為前綴表達式
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <map>
#include <stack>
#include <algorithm>
using namespace std;

void GetInfix(vector<string>& infix)
{
    infix.clear();
    string line;
    getline(cin, line);

    istringstream sin(line);
    string tmp;
    while (sin >> tmp)
    {
        infix.push_back(tmp);
    }
}

// 初始化操作符
void InitOperators(map<string, int>& opers)
{
    opers.clear();
    opers["("] = 100;
    opers[")"] = 900;
    opers["+"] = 100;
    opers["-"] = 100;
    opers["*"] = 200;
    opers["/"] = 200;
}

bool IsOperator(const string& op, const map<string, int>& opers)
{
    auto cit = opers.find(op);
    if (cit != opers.end())
    {
        return true;
    }
    else
    {
        return false;
    }
}

void InfixToPrefix(const vector<string>& infix, vector<string>& prefix, map<string, int>& opers)
{
    prefix.clear();
    stack<string> stk; // 操作符棧
    for (int i = infix.size() - 1; i >= 0; --i) // 從右到左掃描
    {
        if (!IsOperator(infix[i], opers)) // 如果是操作數
        {
            prefix.push_back(infix[i]);
        }
        else // 如果是操作符
        {
            if (infix[i] == ")") // 如果是右括號,則直接入棧
            {
                stk.push(infix[i]);
            }
            else if (infix[i] == "(") // 如果是左括號
            {
                // 依次彈出棧中的操作符,直至遇到右括號
                while (!stk.empty())
                {
                    if (stk.top() == ")")
                    {
                        stk.pop();
                        break;
                    }
                    else
                    {
                        prefix.push_back(stk.top());
                        stk.pop();
                    }
                }
            }
            else // 如果是其他操作符
            {
                while (!stk.empty() && stk.top() != ")" && opers[stk.top()] > opers[infix[i]]) // 棧頂操作符優先級大於當前操作符優先級
                {
                    prefix.push_back(stk.top());
                    stk.pop();
                }
                // 將當前操作符入棧
                stk.push(infix[i]);
            }
        }
    }

    // 檢測操作符棧是否為空
    while (!stk.empty())
    {
        prefix.push_back(stk.top());
        stk.pop();
    }
    // 將prefix翻轉
    reverse(prefix.begin(), prefix.end());
    return;
}

void Display(const vector<string>& fix)
{
    for (auto i = 0; i != fix.size(); ++i)
    {
        cout << fix[i] << ' ';
    }
    cout << endl;
}

int main()
{
    map<string, int> opers;
    InitOperators(opers);

    while (true)
    {
        vector<string> infix, prefix;
        GetInfix(infix);

        Display(infix);

        InfixToPrefix(infix, prefix, opers);
        Display(prefix);
        cout << endl;
    }
    return 0;
}

         首先說明的是,我們的中綴表達式輸入是用空白符間隔的,而沒有對中綴表達式進行詞法分析,對中綴表達式的詞法分析可以參考《四則運算的詞法分析》。

         我們首先實現了中綴表達式的輸入、操作符及其優先級的初始化、判斷是否為操作符。然后重點在中綴表達式轉換為前綴表達式的函數:InfixToPrefix。

         中綴表達式轉換前綴表達式的操作過程為:

         首先設定一個操作符棧,從右到左順序掃描整個中綴表達式,如果是操作數,則直接歸入前綴表達式;如果是操作符,則檢測器是否是右括號,如果是右括號,則直接將其入棧;如果是左括號,則將棧中的操作符依次彈棧,歸入前綴表達式,直至遇到右括號,將右括號彈棧,處理結束;如果是其他操作符,則檢測棧頂操作符的優先級與當前操作符的優先級關系,如果棧頂操作符優先級大於當前操作符的優先級,則彈棧,並歸入前綴表達式,直至棧頂操作符優先級小於等於當前操作符優先級,這時將當前操作符壓棧。

         當掃描完畢整個中綴表達式后,檢測操作符棧是否為空,如果不為空,則依次將棧中操作符彈棧,歸入前綴表達式。最后,將前綴表達式翻轉,得到中綴表達式對應的前綴表達式。

         下面,我們結合中綴表達式轉后綴表達式的過程,比較中綴轉前綴與中綴轉后綴的聯系和區別。

 

中綴轉前綴

中綴轉后綴

操作符棧

操作符棧

掃描順序

從右到左

從左到右

遇到操作數

直接歸入

直接歸入

遇到右括號

直接入棧

將棧中操作符依次彈棧,歸入,直至遇到左括號,將左括號彈棧,處理完畢

遇到左括號

將棧中操作符依次彈棧,歸入,直至遇到右括號,將右括號彈棧,處理完畢

直接入棧

遇到其他操作符

檢測棧頂操作符優先級與當前操作符優先級關系,如果棧頂大於當前,則出棧,歸入,直至棧頂小於等於當前,並將當前操作符入棧

檢測棧頂與當前優先級關系,如果棧頂大於等於當前則出棧,歸入,直至棧頂小於當前,並將當前操作符入棧

操作符棧中的優先級

從棧底到棧頂操作優先級:非遞減。即:棧頂可以大於或等於下面的

從棧底到棧頂優先級:遞增。即:棧頂必須大於下面的

是否翻轉

翻轉

無需翻轉

 

         通過上表,我們可以看出中綴轉前綴與中綴轉后綴的最大區別在於兩點:掃描順序和操作符棧中操作符優先級的排列關系。

 

         總結

         以上我們主要討論了中綴表達式轉換前綴表達式的過程,並與中綴表達式轉換后綴表達式進行了比較,找出其中的差異點。通過本文,將中綴表達式轉換為前綴表達式,以及之前有《前綴表達式的計算》,這樣我們可以通過前綴表達式,計算中綴表達式的值了。即先將中綴表達式轉換為前綴表達式,然后對前綴表達式進行計算,計算結果即為中綴表達式的值。

         下一步,我們將討論如何將前綴表達式轉換中綴表達式,如何將后綴表達式轉換為中綴表達式,以及前綴表達式和后綴表達式之間的直接相互轉換。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM