算數表示式的計算

2021-08-10 08:13:01 字數 4020 閱讀 9147

一、算數表示式的兩種表示

在計算機中進行算數表示式的計算是通過棧來實現的。算數表示式的兩種表示方法:即中綴表示式和字尾表示式。

把雙目運算子出現在兩個運算元中間的這種習慣表示叫做算數表示式的中綴表示,這種算數表示式被稱為中綴算數表示式或中綴表示式。(就是平常我們習慣的表示方式)

例如:2+5*6  

中綴表示式的計算必須遵守以下三條規則:

(1) 先計算括號內,後計算括號外。

(2) 在無括號或同層括號內,先進行乘除運算後進行加減運算。

(3)同一優先順序運算,從左向右依次進行。

把運算子放在兩個運算物件後面,採用字尾表示的算術表示式被稱為字尾算術表示式或字尾表示式。在字尾表示式中,不存在括號,也不存在運算子優先順序的差別,計算過程完全按照運算子出現的先後次序進行,整個計算過程僅需掃瞄一遍即可完成。

中綴算術表示式轉換成對應的字尾算術表示式的規則是:把兩個運算子都移到它的兩個運算物件的後面,並用空格填補原來運算子位置,然後刪除掉所有的括號即可。

例如,對於下列各中綴表示式

(1)3/5+6

(2)16-9*(4+3)

(3)2*(x+y)/(1-x)

(4)(25+x)*(a*(a+b)+b)

對應的字尾表示式分別為:

(1)3 5/ 6+

(2)16 9 4 3+*-

(3)2 x y+* 1 x - /

(4)25 x + a a b+* b+ *

二、字尾表示式求值的演算法

1. 字尾表示式的求值演算法

字尾表示式的求值,掃瞄一遍即可完成。它需要使用乙個棧,假定用sck表示,其元素型別應為運算元的型別,假定為浮點型double,用此棧儲存字尾表示式中的運算元、計算過程中的中間結果以及最後結果。字尾表示式求值演算法的基本思路是:對於乙個以後綴算術表示式為內容的字串,每次從該字串中讀入乙個字元,若它是空格則不做任何處理,若它是運算子,則表明它的兩個運算元已經在棧sck中,其中棧頂元素為運算子的後乙個運算元,棧頂元素的前乙個運算元,把它彈出後進行相應運算並儲存到乙個雙精度變數(假定為x)中,否則,掃瞄到的字元必為數字或小數點,應把從此開始的雙精度浮點數字串轉換為乙個浮點數並存入x中,然後把計算或轉換得到的浮點數(即x的值)壓入到sck棧中,依次向下掃瞄每乙個字元並進行上述處理,當處理字尾表示式結束後,最終結果儲存在棧中,並且棧中僅存這乙個值,把它彈出返回即可。整個演算法描述為:

//計算字串str中的字尾表示式的值

public static double compute(string str)

else //除數為0時終止執行

i++;

break;

default: //掃瞄到的若是浮點數字串,生成對應的浮點數

if((a[i]<'0'||a[i]>'9')&&a[i]!='.')

x=0.0; //利用x儲存掃瞄到的整數部分的值

while(a[i]>=48 && a[i]<=57) //48是字元0的ascll碼

if(a[i]=='.') //轉換小數部分

x+=y; //把小數部分合併到整數部分x中

}}//switch語句結束

sck.push(x); //把掃瞄轉換後或進行相應運算後得到的乙個浮點數壓入棧中

}//while語句結束

if(sck.isempty()) //若計算結束後棧為空則終止執行

x=(double)sck.pop();

if(!sck.isempty()) //若棧中僅有乙個元素,則它就是字尾表示式的值,否則為出錯

return x; //返回字尾表示式的值

}

此演算法的執行時間主要花費在while( i

2. 把中綴表示式轉換為字尾表示式的演算法

設中綴算術表示式已經儲存在具有string型別的s字串中,轉換後得到的字尾算術表示式擬存於可改變的字串型別(stringbuffer)物件sb中,演算法結束時再轉換為一般的字串型別(string)的物件返回。由中綴表示式轉換為字尾表示式的規則可知:轉換前後,表示式中的數值項的次序不變。而運算子的次序發生了變化,由處在兩個運算物件的中間變為處在兩個運算物件的後面,同時去掉了所有的括號。為了使轉換正確,必須設定乙個運算子棧,並在棧底開始放入乙個特殊運算子,假定為『@』字元,讓它具有最低的運算子優先順序,假定其優先順序設定為數值0,此棧用來儲存掃瞄中綴表示式所得到的暫不能放入字尾表示式中的運算子,待它的兩個運算物件都放入到字尾表示式以後,在令其出棧寫入到字尾表示式中。

把中綴表示式轉換為字尾表示式演算法的思路是:從頭到尾掃瞄中綴表示式中的每個字元(以『@』作為結束標記),對於不同型別的字元按不同情況進行處理。若遇到的是空格則認為是分隔符,不需要進行任何處理;若遇到的是數字或小數點,則直接寫入到s2中,並在每個數值的後面寫入乙個空格;若遇到的是中綴表示式結束符『@』,則退出迴圈處理過程,接著進行結束和返回處理;若遇到的是左括號,則應把它壓入到運算子棧中,待以它開始的括號內的表示式轉換完畢後再出棧;如遇到的是右括號,則表明括號內的中綴表示式已經掃瞄完畢,把從棧頂直到儲存著的對應左括號之間的運算子依次退棧並寫入到sb串的結尾處;若遇到的是運算子,當該運算子的優先順序大於棧頂運算子的優先順序(加減運算子的優先順序設定為1,乘除運算子的優先順序設定為2,在棧底儲存的特殊運算子『@』和左括號運算子『(』的優先順序設定為0)時,表明該運算子的後乙個運算物件還沒有被掃瞄並放入到sb串中,應把它暫存於運算子棧中,待它的後乙個運算物件從s串中讀出並寫入到sb串之後,再令其出棧並寫入sb串中;若遇到的運算子的優先順序小於等於棧頂運算子的優先順序,表明棧頂運算子的兩個運算物件已經被儲存到sb串中,應將棧頂運算子退棧並寫入到sb串找那個,對於新的棧頂運算子仍繼續進行比較和處理,直到被處理的運算子的優先順序大於棧頂運算子的優先順序為止,然後再將該運算子進棧。

按照以上過程掃瞄到中綴表示式字串的結尾符『@』時,應把棧中剩餘的運算子依次退出棧並寫入到字尾表示式中,整個轉換過程就處理完畢,在sb中就得到了轉換後的字尾表示式,把它轉換成一般的字串物件返回即可。

將中綴算術表示式轉換為字尾算術表示式的演算法描述如下():

//將字串s中儲存的中綴表示式(以『@』結尾)轉換為字尾表示式並返回

public static string change(string s)

sck.push(ch); //把ch運算子寫入棧中

ch=a[++i];

}//此處必然為數字或小數點字元,否則為中綴表示式錯誤

else

//把乙個數值中的每一位依次寫入到sb的字串的末尾

while((ch>='0'&&ch<='9')||ch=='.')

//在sb的每個數值後面放入乙個空格字元

}} //做演算法的結束處理,把暫存在棧中的運算子依次退棧並寫入到sb末尾

ch=(character)sck.pop();

while(ch!='@')

else

}//把可變化的字串物件sb轉換為string物件並返回

return new string(sb); }

//在上面的演算法中用到了precedence(char op)方法,它返回運算子op的優先順序,該方法的具體定義為:

public static int precedence(char op)

}

在上面的中綴轉後字尾的演算法中,中綴算術表示式中的每個字元均需要掃瞄一遍,對於從s中稻苗得到的每個運算子,最多需要進行sck棧、出sck棧和寫入sb字尾表示式這3次操作,對於從s中掃瞄得到的每個數字或小數點,只需要把它直接寫入到sb字尾表示式即可。所以,此演算法的時間複雜度為o(n),n為字尾表示式中字元的個數。該演算法需要使用乙個運算子棧,需要的深度不會超過中綴表示式中運算子的個數,所以此演算法的空間複雜度之多也為o(n)。

利用棧計算算數表示式的值

先將中綴表示式利用棧轉換為字尾表示式,然後再利用棧由字尾表示式計算算數表示式的值,具體 如下 include using namespace std include include include enum type enum operat struct cell input 1 2 3 4 5 中...

中綴算數表示式的求值問題

void convertpostexp char str,char str1 把中綴表示式轉換成字尾表示式,轉換過程需要用到棧,具體過程如下 1 設定乙個堆疊,初始時將棧頂元素置為 2 順序讀入中綴算數表示式,當讀到的單詞為運算元時就將其輸出,並接著讀下乙個單詞 3 當讀到的單詞為運算子時,令x1為...

5 算數運算子及算數表示式

在計算機語言中,用運算子將操作物件連線起來就構成了表示式,這與數學中的表示式類似。運算子按運算性質可分為算術運算子 關係運算子 邏輯運算子等。本節介紹一下python3的算數運算子及算數表示式。python3中的算數運算子有7種 上面就是加 減 乘 除四種最基本的算數運算子。a 10b 5sum a...