1. 程式人生 > 其它 >逆波蘭式

逆波蘭式

一.前言:

  逆波蘭表示法 ( Reverse Polish notation , RPN ,或 逆波蘭記法 ),是一種是由 波蘭 數學家 揚·武卡謝維奇 1920年引入的數學表示式形式,在逆波蘭記法中,所有 操作符 置於 運算元 的後面,因此也被稱為 字尾表示法 (也稱字尾表示式)。而我們平常用的a+b叫做中綴表示式,轉換成字尾表示式為ab+(其實還有一個波蘭式,也就作字首表示式+ab),為什麼要這麼轉換呢?雖然我們人腦非常喜歡這種顯而易見的中綴表示式計算,但是計算機算覺得這非常的難計算(主要是堆疊的實現會變的比中綴表示式更簡單),因此就有了波蘭表示式和逆波蘭表示式。

二.問題分析:

  那我們如和將中綴表示式轉成字尾表示式呢?總所周知,在中綴表示式中我們的操作符+-優先順序最低,*/優先順序第二,而()優先順序最高。但是在逆波蘭式的轉換過程中這個優先順序有一些變化,乘除的優先順序會看成比加減的優先順序更低,括號優先順序依舊是最高,因此我們可以有定義+-優先順序為2,()優先順序為1,*/優先順序為3。因此我們就解決掉了優先順序的問題。

  其他規則

  1.如果碰到左括號,則直接入棧。

  2.如果碰到優先順序高於棧頂的,則依次出棧,直到棧頂為空或者棧頂的優先順序高於碰到的操作符,然後再把操作符加入棧區即可

  3.如果中綴表示式遍歷完成後,棧區還剩餘操作符,則直接把剩餘操作符從棧頂依次加入逆波蘭式

  4.如果碰到右括號,則把括號和右括號之間的操作符加入逆波蘭式,左括號和右括號出棧

  接下來我們看看具體怎麼轉換吧!

  

  首先,我們給出一個計算樣例來解釋計算過程,中綴表示式如下:1+2*(3+4)/5

  我們給出一個棧區用來存操作符,用一個字串來儲存逆波蘭式

  碰到1,直接加入逆波蘭式

  stack(代表棧區):NULL

  bolan(代表逆波蘭式):1

  

  碰到‘+’,因為棧區此時為空,故直接加入棧區

  stack(代表棧區):+

  bolan(代表逆波蘭式):1

  碰到2,直接加入逆波蘭式

  stack(代表棧區):NULL

  bolan(代表逆波蘭式):1,2

  碰到‘*’,因為*的優先順序為2,最低,故不需要彈出+號,因此直接入棧\

  stack(代表棧區):+,*

  bolan(代表逆波蘭式):1,2

  

  碰到‘(’,因為左括號需要續')'相匹配,故直接入棧

  stack(代表棧區):+,*,(

  bolan(代表逆波蘭式):1,2

  

  

  碰到數字3,直接加入逆波蘭式

  stack(代表棧區):+,*,(

  bolan(代表逆波蘭式):1,2,3

   

  碰到‘+’,因為+優先順序低於括號,因此直接入棧

  stack(代表棧區):+,*,(,+

  bolan(代表逆波蘭式):1,2,3

  碰到數字4,直接加入逆波蘭式

  stack(代表棧區):+,*,(,+

  bolan(代表逆波蘭式):1,2,3,4

  碰到‘(',把左括號之前的全部加入逆波蘭式

  stack(代表棧區):+,*

  bolan(代表逆波蘭式):1,2,3,4,+

  碰到’/',把棧頂優先順序不高於'/'的全部加入逆波蘭式,再把自己加入棧區

  stack(代表棧區):+,/

  bolan(代表逆波蘭式):1,2,3,4,+,*

  碰到數字5,直接加入波蘭式

  stack(代表棧區):+,/

  bolan(代表逆波蘭式):1,2,3,4,+,*,5

  字串遍歷結束,把棧區剩下的全部加入逆波蘭式

  

  stack(代表棧區):NULL

  bolan(代表逆波蘭式):1,2,3,4,+,*,5,/,+

三.程式碼實現:

 1 #include "bits/stdc++.h"
 2 using namespace std;
 3 int jdgCode(char flag)//定於操作符運算
 4 {
 5     if(flag == '+')
 6         return 1;
 7     if(flag == '-')
 8         return 2;
 9     if(flag == '*')
10         return 3;
11     if(flag == '/')
12         return 4;
13 }
14 double Compute(string cpu)
15 {
16     stack <double> ans;
17     for(auto iter = cpu.begin();iter != cpu.end();iter++){
18         if(*iter >= '0' && *iter <= '9')
19             ans.push(*iter - '0');
20         else {
21             double r1,r2;
22             r1 = ans.top();
23             ans.pop();
24             r2 = ans.top();
25             ans.pop();
26             switch(jdgCode(*iter)){
27                 case 1: ans.push(r2 + r1);break;
28                 case 2: ans.push(r2 - r1);break;
29                 case 3: ans.push(r2 * r1);break;
30                 case 4: ans.push(r2 / r1);break;
31             }
32         }
33     }
34     return ans.top();
35 }
36 int prio(char a)
37 {
38     if(a == '*' || a == '/')
39         return 2;
40     else if(a == '+' || a == '-')
41         return 1;
42     else 
43         return 0;//左括號優先順序
44 }
45 void Dispose(string& ms,string& as)//處理成字尾表示式
46 {
47     stack <char> ct;//定義一個ct容器儲存運算子
48     for(auto iter = ms.begin();iter != ms.end();iter++){
49         if(*iter >= '0' && *iter <= '9')//如果是數字,直接入棧
50             as += *iter;
51         else{
52             if(ct.empty() || *iter == '(')//如果是空棧,或者是左括號,直接入棧
53                 ct.push(*iter);
54             else if(*iter == ')'){
55                 while(ct.top() != '('){//把左括號和有括號裡面的操作符出棧
56                     as += ct.top();
57                     ct.pop();
58                 }
59                 ct.pop();//彈出左括號
60             }
61             else{
62                 while(!ct.empty() && prio(*iter) <= prio(ct.top())){//把優先順序低於當前操作符的操作符出棧
63                     as += ct.top();
64                     ct.pop();
65                 }
66                 ct.push(*iter);//把當前操作符入棧
67             }
68         }
69     }
70     while(!ct.empty()){//如果棧區還有操作符
71         as += ct.top();
72         ct.pop();
73     }
74 }
75 int main()
76 {
77     string ms;//中綴表示式
78     string as;//字尾表示式
79     cin >> ms;
80     Dispose(ms,as);//將中綴表示式處理為字尾表示式
81     cout << as << endl;//輸出處理後的字尾表示式
82     cout << "Result:" << Compute(as) << endl;//輸出字尾表示式計算結果
83     return 0;
84 }