用棧和佇列實現中綴表示式的求解

2021-06-27 00:24:22 字數 3388 閱讀 7168

今天為了複習棧和佇列的相關知識,所以嘗試著用c寫了一段求解中綴表示式的程式。主要分兩步實現:一是完成中綴表示式到字尾表示式的轉換,二是實現中綴表示式的求解。

用棧可以比較方便地將中綴表示式轉化為字尾表示式,舉個例子,如果我們從控制台輸入這樣乙個中綴表示式:12+5*(4+2*3)-6,那麼它對應的字尾表示式就是12 5 4 2 3 * + * + 6 -。那麼,我們怎樣用棧實現這個中綴表示式到它所對應的字尾表示式的轉換呢?首先我們需要定義乙個棧,用於轉換表示式,另外我們還需要乙個佇列來儲存轉換結果,以便進行下一步的求解。值得注意的是從控制台輸入的表示式是儲存在緩衝區的,而緩衝區中實際上依次儲存這樣的一串字元:『1』 』2『 』+『 』5『 』*『 』(『 』4『 』+『 』2『 』*『 』3『 』)『 』-『 』6『 』\n'。用getchar()依次讀取字元,接下去的操作是這樣的:

『1』 』2『是數字,直接入佇列;

發現』+『,因為是第乙個運算子所以入棧儲存;

』5『是數字 ,直接入佇列,入佇列;

發現 』*『,因為 』*『的優先順序比『+』高,所以『5』不是『+』的右運算元,要先知道『*』的又運算元才能知道『+』的右運算元,『*』入棧;

發現『(』,無條件入棧,在遇到『)』之前我們都不知道『*』的右運算元是誰。

『4』是數字,入佇列;

發現』+『,因為是『(』後的第乙個運算子所以入棧儲存;

『2』是數字,入佇列;

發現『*』,因為』*『的優先順序比『+』高,所以『2』不是『+』的右運算元,『*』入棧;

『3』是數字,入佇列;

發現『)』,說明『3』確實是』*『的右運算元,依次輸出取走棧頂的操作符,放入佇列中,直到發現『(』,『(』只出棧,不入佇列;

發現『-』,因為棧頂是』*『,比『-』優先順序高,說明前面的一整坨是』*『的右運算元,『*』出棧,入佇列,接著『+』出棧,入佇列,棧已空,『-』入棧;

『6』是數字,入佇列;

發現『\n』,說明輸入結束,輸出棧中的所有運算子,『-』出棧,入佇列。

這樣,佇列中儲存的就是逆波蘭表示式,值得注意的是,在發現預算符和『\n』之後,要在佇列中插入乙個空格,因為數與數之間要用空格加以區分,還有在每個運算子出棧之後,也要在佇列中插入空格,以隔開不同的運算子。下面總結一下具體的處理規則:

發現數字,直接入佇列;

發現』+『或『-』,將依次取出棧頂元素,入佇列,直到遇到『(』或棧底;

發現』*『或』/『,如果棧頂元素是』*『或』/『,則取出棧頂元素,入佇列,直到棧頂元素不是』*『或』/『為止;

發現『(』,直接入棧;

發現『)』,依次取出棧頂元素,入佇列,直到遇到『(』;

發現『\n』,輸出棧中的所有運算子,直到棧底。

下面是實現這一過程的**片段:

while(1)

else if('\n' == inputchar)

break;

} else if('*' == inputchar || '/' == inputchar)

pushchar(cstack, inputchar);

} else if('+' == inputchar || '-' == inputchar)

pushchar(cstack, inputchar);

} else if('(' == inputchar)

else if(')' == inputchar)

if(cstack ->base == cstack ->top)

popchar(cstack, &outputchar);

insertqueue(cqueue, outputchar);

insertqueue(cqueue, ' ');

} }}

值得注意的就是空格的插入,得到的逆波蘭表示式儲存在cqueue指向的佇列中。

接下去的步驟就是依次取出cqueue佇列中隊頭的元素,計算佇列中儲存的逆波蘭表示式。這裡要用另乙個棧來計算逆波蘭表示式的結果,依然使用前面的例子,我們在上一步中得到的逆波蘭表示式為12 5 4 2 3 * + * + 6 -,這個表示式是怎麼計算的呢?首先,從左往右讀取每個元素,讀到第乙個運算子是『*』,計算2*3=6,下一步,讀到『+』,計算4+6=10,下一步,讀到『*』,計算5*10=50,下一步,讀到『+』,計算12+50=62,然後讀到數字6,跳過,讀到最後乙個運算子『-』,計算62-6=56,ok,最終結果就是56。我們發現,這種從後往前的計算方式和棧的處理驚人地相似。所以我們完全可以定義乙個棧來處理這個問題,處理的策略如下:

凡是讀到數字直接推到棧中(注意佇列中的數字用空格隔開);

如果讀到操作符,取出棧底元素,那麼該元素就是運算子的右運算元,再次取出棧底元素,那麼該元素就是運算子的左運算元,計算運算結果,然後壓入棧中;

如果逆波蘭表示式是正確的,那麼當佇列清空之後,棧中只剩乙個元素,那麼這個元素就是我們的計算結果。

下面是這一過程的實現**:

inputint = 0;

while(1)

printf("計算結果為: %d\n", tempint1);

return 0;

} deletequeue(cqueue, &inputchar);

if((inputchar >= '0') && (inputchar <= '9'))

pushint(istack, inputint);

inputint = 0;

} else if(inputchar == '+')

pushint(istack, tempint1 + tempint2);

} else if(inputchar == '-')

pushint(istack,tempint1 - tempint2);

} else if(inputchar == '*')

pushint(istack,tempint1 * tempint2);

} else if(inputchar == '/')

pushint(istack,tempint1 / tempint2);

}}

這段**中值得一提的就是對數字的處理,首先,如果我們讀到了第乙個數字,那麼先把它儲存在乙個變數inputint中,如果下一次讀到的還是乙個數字,那麼將原來的inputint變數乘以10然後加上讀到的數字,如果讀到的不是數字,那麼就將inputint放到棧頂,並將inputint變數清零。這樣我們就把一串字元轉化成了乙個整型變數了。

這樣通過這兩步我們就可以計算出乙個整型的中綴表示式的計算結果了。其實問題就是怎樣管理數與數之間的計算順序,也就是先括號,後乘除,最後才是加減。或者說就是先乘除後加減,而括號就是用來破壞這一規則的。那麼整個過程就是討論『+』 『-』 『*』 『/』的運算順序 ,而字尾表示式可以很清楚地表達這種順序:從左往右,只要遇到運算子,就把前兩個數作為該運算子的運算元,並計算其結果,依次類推,直到計算出最後結果。所以轉化成字尾表示式之後可以更方便地計算出表示式的結果。

棧求解中綴表示式

表示式求值是進行資料處理的最基本操作。請編寫程式完成乙個簡單算術表示式的求值。要求如下 1 運算子包括 乘方 括號 2 運算量為數值常量,根據自己的能力可以對運算量做不同的約束,例如1位整數 多位整數 實數等 會有不同的測試用例 輸入 一行,即表示式,以 結束。例如 5 8 3 6 5 輸出 一行,...

C用棧實現中綴表示式轉字尾表示式

include include include define maxsize 100 設順序表的最大長度為100,可依具體情況分配空間 typedef char datatype typedef struct datatype data maxsize int top 棧頂指標 seqstack 順...

用陣列順序棧實現表示式運算 中綴表示式

只有關鍵的運算部分有 只要例項化,棧是根據教科書上的寫的,如果要用stl可以修改下就可以用,這個是中序表示式的運算,由於按照老師要求,可能寫的有點繁瑣.include include seqstack.h 教科書上的順序陣列棧,改為相應的stl棧函式就可以直接例項化呼叫class calculato...