前綴、中綴、後綴表達式之間的相互轉換及部分實現

背景介紹

前綴表達式(又稱爲波蘭表達式)
中綴表達式
後綴表達式(又稱爲逆波蘭表達式)

平時我們見到的都是:2+3*5,這樣的算數表達式(中綴),我們數學中也就是用這種
這種表達式(中綴)只適合人來讀寫,不適合計算機,所以爲了方便計算機讀取正確的表達式就有了前綴後綴表達式

本文將會介紹 :

前綴轉中綴,中綴轉前綴
中綴轉後綴,後綴轉中綴
前後綴之間的相互轉換可以用中綴作爲中間商來解決,或者也可以構造語法樹遍歷來解決

前綴轉後綴的具體實現代碼(構造樹實現)
https://www.cnblogs.com/breakthings/p/4053444.html


例子:2+(3-1)*4(中綴,語法樹中序遍歷可以得到)
231-4 * + (後綴,語法樹後序遍歷可以得到,其他方法得到也行,表達式不唯一)
+2*-314 (前綴,語法樹先序遍歷可以得到)

爲了方便理解,我畫了表達式的 語法樹
葉子節點都是,非葉子節點都是運算符。畫圖很簡單就不贅述了

在這裏插入圖片描述

1. 中綴轉前綴

如果僅僅是寫題目,僅需把語法樹用前序遍歷(又稱爲先序遍歷)一遍即可得到答案 +2*-314(前綴表達式)

但一般實現是使用

思路:

  1. 首先要處理字符串,運算符的優先級,多位數字看成整體(比如23看成一個整體而不是2和3),我的例子中沒那麼複雜
  2. 創建兩個棧,一個是數字棧(裏面存的是最終結果),一個是運算符棧
  3. 從右往左 掃描中綴表達式
  4. 若是運算符,則與運算符棧頂元素比較優先級:
    若該運算符優先級大於等於棧頂元素,則將該運算符入棧;
    若該運算符優先級小於棧頂元素,則運算符棧內元素出棧並壓入數字棧,再與其比較,直到該運算符優先級大於等於棧頂元素的優先級時,將該運算符壓入棧中。
  5. 注意:我們先在運算符棧中壓入一個‘#’ 規定其優先級爲最低 這樣解決了開始時候的邊界問題)
    注意:遇到右括號直接壓入棧中,遇到一個左括號,那麼就將運算符棧元素彈出並壓入數字棧直到遇到右括號,並且把右括號彈出,停止彈出。這個過程,兩個括號都不加入數字棧。
  6. 表達式遍歷完後,若運算符棧還有元素,則依次彈出壓入數字棧。
  7. 把數字棧元素從棧頂依次彈出,就得到前綴表達式。

代碼實現:

例:1-(2+3) 轉換前綴是:- 1 + 2 3
例:1+((2+3)*4)-5 轉換前綴是:- + 1 * + 2 3 4 5
例:123+((246+39)*48)-55 轉換前綴是:- + 123 * + 246 39 48 55

參考博客:https://blog.csdn.net/holly_Z_P_F/article/details/98724274

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=1005;
typedef struct NODE{
    string ch;
    int level;
}NODE;
NODE node[maxn];
string s;
int change(){
    int w1=0;
    for(int i=0;i<s.size();i++){  //劃分優先級
        if(s[i]=='*'||s[i]=='/'){
            node[w1].ch=s[i];
            node[w1++].level=2;
        }
        else if(s[i]=='+'||s[i]=='-'){
            node[w1].ch=s[i];
            node[w1++].level=1;
        }
        else if(s[i]=='('||s[i]==')'){
            node[w1].ch=s[i];
            node[w1++].level=0;
        }
        else if(s[i]>='0'&&s[i]<='9'){ //分割字符串
            int j=i;
            while(s[j]>='0'&&s[j]<='9'){ j++;}
            node[w1].ch=s.substr(i,j-i);
            node[w1].level=100;
            w1++;
            i=j-1;
        }
    }
    return w1;
}
void solove(int l){
    NODE ans[maxn]; //結果棧
    NODE q[maxn];  //運算符棧
    int w2=0,w3=0;
    q[w3].ch="#";  q[w3++].level=-1;//先壓入 #
    for(int i=l-1;i>=0;i--){
        if(node[i].level==100){
            ans[w2++]=node[i];
        }
        else{
            if(node[i].ch==")") q[w3++]=node[i];
            else if(node[i].ch=="("){
                while(q[w3-1].ch!=")"){
                    w3--; ans[w2++]=q[w3];//壓入結果棧
                }
                w3--;
            }
            else{
                while(node[i].level<q[w3-1].level){ //比較優先級
                    w3--; ans[w2++]=q[w3];
                }
                q[w3++]=node[i];
            }
        }
    }
    while(w3!=1){
        w3--;  ans[w2++]=q[w3];
    }
    for(int i=w2-1;i>=0;i--){//倒序輸出
        cout<<ans[i].ch<<" ";
    }
    return ;
}
int main(){
    cin>>s;        //輸入表達式
    int l=change();//處理表達式
    solove(l);     //轉換爲前綴表達式
    return 0;
}

2. 前綴轉中綴

(這一點網上的資料很少)
例子:+2*-314(前綴)-----> 2+((3-1)*4)(中綴)

思路:

準備一個棧

  1. 從右往左掃描前綴表達式
  2. 遇見數字壓入數字棧
  3. 遇見運算符棧,則彈出數字棧的兩個元素,並且運算,前後還要添加括號,然後壓入棧
    例如:棧中有2和3(2個元素),現在遇見+了,則把 (2+3) 壓入棧,棧中現在就有5個元素了,後面的依次類推
    結果中肯定會出現很多多餘的括號,也可以解決但是比較複雜就不詳細說了

代碼實現:

實現起來較爲複雜,有機會補上…

3. 中綴轉後綴

寫答案的話後序遍歷的語法樹,可以直接得到答案

思路:

和中綴轉前綴差不多,只是方向改變了

  1. 從左往右掃描中綴表達式
  2. 其他的與中綴轉前綴的操作一樣

這裏有一篇圖解博客,方便大家理解
https://www.cnblogs.com/lanhaicode/p/10776166.html

4. 後綴轉中綴

思路:

與前綴轉中綴的思路一樣

  1. 從右往左掃描後綴表達式
  2. 遇見數字壓入數字棧
  3. 遇見運算符棧,則彈出數字棧的兩個元素,並且運算,前後還要添加括號,然後壓入棧
    例如:棧中有2和3(2個元素),現在遇見+了,則把 (2+3) 壓入棧,棧中現在就有5個元素了,後面的依次類推

1 2 3 + 4 *5 - +

例如:
從左往右掃描先碰到+號,取+號前面兩個操作數:2,3 得到:(2+3).
繼續往下掃碰到*號,取4 和2+3 得到:((2+3)*4)
-號,取(2+3)*4和5得到::(((2+3)*4)-5))
+號:取(2+3)*4-5和1得到::1+(((2+3)*4)-5))
如果把多餘的括號省略就是1+(2+3)*4-5


如有錯誤,不吝賜教

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章