日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

将表达式转换成逆波兰式

發布時間:2024/9/30 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 将表达式转换成逆波兰式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://www.cnblogs.com/stay-foolish/archive/2012/04/25/2470590.html

假設表達式由單字母變量和雙目四則運
算算符構成。試寫一個算法,將一個通常書寫形式
且書寫正確的表達式轉換為逆波蘭式。

實現下列函數:
char *RPExpression(char *e);
/* 返回表達式e的逆波蘭式 */

Stack是一個已實現的棧。
可使用的相關類型和函數:
typedef char SElemType; // 棧Stack的元素類型
Status InitStack(Stack &s);
Status Push(Stack &s, SElemType e);
Status Pop(Stack &s, SElemType &e);
Status StackEmpty(Stack s);
SElemType Top(Stack s);

-------------------------------------------------------------------------------------------------

二、思路

  拿到題目,要做的第一件事情,就是搞懂題目究竟要我們做什么,很顯然,題目中的關鍵字是“逆波蘭式”,那么首先我們要搞懂這個概念。

  所謂的逆波蘭表示法Reverse Polish notationRPN,或逆波蘭記法),是一種數學表達式方式,在逆波蘭記法中,所有操作符置于操作數的后面,因此也被稱為后綴表示法。逆波蘭記法不需要括號來標識操作符的優先級。(摘自維基)

  舉個簡單的例子,平常我們寫的數學表達式a+b,就是一種中綴表達式,寫成后綴表達式就是ab+。再舉一個復雜的例子,中綴表達式(a+b)*c-(a+b)/e的逆波蘭式是ab+c*ab+e/-。

  在弄清楚概念以及題目的要求之后,接下來就要編寫算法了。那么將一個表達式轉換為逆波蘭式的算法思想是什么呢?

?

  (1)首先,需要分配2個棧,棧s1用于臨時存儲運算符(含一個結束符號),此運算符在棧內遵循越往棧頂優先級越高的原則;棧s2用于輸入逆波蘭式,為方便起見,棧s1需先放入一個優先級最低的運算符,在這里假定為'#';

?

  (2)從中綴式的左端開始逐個讀取字符x,逐序進行如下步驟:

      1.若x是操作數,則分析出完整的運算數(在這里為方便,用字母代替數字),將x直接壓入棧s2;

      2.若x是運算符,則分情況討論:

          若x是'(',則直接壓入棧s1;

          若x是')',則將距離棧s1棧頂的最近的'('之間的運算符,逐個出棧,依次壓入棧s2,此時拋棄'(';

          若x是除'('和')'外的運算符,則再分如下情況討論:

              若當前棧s1的棧頂元素為'(',則將x直接壓入棧s1;

              若當前棧s1的棧頂元素不為'(',則將x與棧s1的棧頂元素比較,若x的優先級大于棧s1棧頂運算符優先級,則將x直接壓入棧s1。否者,將棧s1的棧頂運算符彈出,壓入棧s2中,直到棧s1的棧頂運算符優先級別低于(不包括等于)x的優先級,或棧s2的棧頂運算符為'(',此時再則將x壓入棧s1;

?【第二步是一個循環,要把中綴式讀完。第三步是在循環之外】

  (3)在進行完(2)后,檢查棧s1是否為空,若不為空,則將棧中元素依次彈出并壓入棧s2中(不包括'#');      ?

  

  (4)完成上述步驟后,棧s2便為逆波蘭式輸出結果。但是棧s2應做一下逆序處理,因為此時表達式的首字符位于棧底;

-------------------------------------------------------------------------------------------------

大家可以用上述算法計算 x=d-a*(e+c)/f


后綴表達式是:xdaec+*f/-=

有一個快速檢測是否寫錯的方法:

后綴表達式的運算的對象的順序和中綴式對象的順序是相同的

三、代碼(C/C++)?

C代碼 1 char *RPExpression(char *e) 2 /* 返回表達式e的逆波蘭式 */ 3 { 4 //棧s1用于存放運算符,棧s2用于存放逆波蘭式 5 Stack s1,s2; 6 InitStack(s1); 7 InitStack(s2); 8 9 //假設字符'#'是運算級別最低的運算符,并壓入棧s1中 10 Push(s1,'#'); 11 12 //p指針用于遍歷傳入的字符串,ch用于臨時存放字符,length用于計算字符串長度 13 char *p=e,ch; 14 int length=0; 15 for(;*p!='\0';p++)//逐個字符訪問 16 { 17 switch(*p) 18 { 19 //遇'('則直接入棧s1 20 case '(': 21 Push(s1,*p); 22 break; 23 //遇')'則將距離棧s1棧頂的最近的'('之間的運算符,逐個出棧,依次送入棧s2,此時拋棄'(' 24 case ')': 25 while(Top(s1)!='(') 26 { 27 Pop(s1,ch); 28 Push(s2,ch); 29 } 30 Pop(s1,ch); 31 break; 32 //遇下列運算符,則分情況討論: 33 //1.若當前棧s1的棧頂元素是'(',則當前運算符直接壓入棧s1; 34 //2.否則,將當前運算符與棧s1的棧頂元素比較,若優先級較棧頂元素大,則直接壓入棧s1中, 35 // 否則將s1棧頂元素彈出,并壓入棧s2中,直到棧頂運算符的優先級別低于當前運算符,然后再將當前運算符壓入棧s1中 36 case '+': 37 case '-': 38 for(ch=Top(s1);ch!='#';ch=Top(s1)) 39 { 40 if(ch=='(') 41 { 42 break; 43 } 44 else 45 { 46 Pop(s1,ch); 47 Push(s2,ch); 48 } 49 } 50 Push(s1,*p); 51 length++; 52 break; 53 case '*': 54 case '/': 55 for(ch=Top(s1);ch!='#'&&ch!='+'&&ch!='-';ch=Top(s1)) 56 { 57 if(ch=='(') 58 { 59 break; 60 } 61 else 62 { 63 Pop(s1,ch); 64 Push(s2,ch); 65 } 66 } 67 Push(s1,*p); 68 length++; 69 break; 70 //遇操作數則直接壓入棧s2中 71 default: 72 Push(s2,*p); 73 length++; 74 } 75 } 76 //若棧s1非空,則將棧中元素依次彈出并壓入棧s2中 77 while(!StackEmpty(s1)&&Top(s1)!='#') 78 { 79 Pop(s1,ch); 80 Push(s2,ch); 81 } 82 //最后將棧s2輸出,逆序排列成字符串; 83 char *result; 84 result=(char *)malloc(sizeof(char)*(length+1)); 85 result+=length; 86 *result='\0'; 87 result--; 88 for(;!StackEmpty(s2);result--) 89 { 90 Pop(s2,ch); 91 *result=ch; 92 } 93 ++result; 94 return result; 95 }

-------------------------------------------------------------------------------------------------?

四、總結

?  對于實現逆波蘭式算法,一開始不懂得概念的時候的確不知道如何入手,在摸清思路后,其實難度并不大,關鍵在于邏輯要清晰,而且要細心,寫這段代碼的時候很痛苦,共用了兩天的時間(真的好菜)。

  另摘錄維基及度娘中關于實現逆波蘭式的意義:(摘自百度)

    為什么要將看似簡單的中序表達式轉換為復雜的逆波蘭式?原因就在于這個簡單是相對人類的思維結構來說的,對計算機而言中序表達式是非常復雜的結構。相對的,逆波蘭式在計算機看來卻是比較簡單易懂的結構。因為計算機普遍采用的內存結構是棧式結構,它執行先進后出的順序。    

  

  逆波蘭式的意義:(摘自維基)

    當有操作符時就計算,因此表達式并不是從右至左整體計算而是每次由中心向外計算一部分,這樣在復雜運算中就很少導致操作符錯誤。

    堆棧自動記錄中間結果,這就是為什么逆波蘭計算器能容易對任意復雜的表達式求值。與普通科學計算器不同,它對表達式的復雜性沒有限制。

    逆波蘭表達式中不需要括號,用戶只需按照表達式順序求值,讓堆棧自動記錄中間結果;同樣的,也不需要指定操作符的優先級。

    逆波蘭計算器中,沒有“等號”鍵用于開始計算。

    逆波蘭計算器需要“確認”鍵用于區分兩個相鄰的操作數。

    機器狀態永遠是一個堆棧狀態,堆棧里是需要運算的操作數,棧內不會有操作符。

    教育意義上,逆波蘭計算器的使用者必須懂得要計算的表達式的含義。


問題2:如何求出逆波蘭式?

下面以(a+b)*c為例子進行說明:

  (a+b)*c的逆波蘭式為ab+c*,假設計算機把ab+c*按從左到右的順序壓入棧中,并且按照遇到運算符就把棧頂兩個元素出棧,執行運算,得到的結果再入棧的原則來進行處理,那么ab+c*的執行結果如下:   1)a入棧(0位置)   2)b入棧(1位置)   3)遇到運算符“+”,將a和b出棧,執行a+b的操作,得到結果d=a+b,再將d入棧(0位置)   4)c入棧(1位置)   5)遇到運算符“*”,將d和c出棧,執行d*c的操作,得到結果e,再將e入棧(0位置)   經過以上運算,計算機就可以得到(a+b)*c的運算結果e了。


總結

以上是生活随笔為你收集整理的将表达式转换成逆波兰式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。