通過鍵盤輸入乙個表示式,如21-(15+7*9)/3,要求將其轉換為字尾表示式,並計算表示式的值。
【分析】求表示式的值是高階程式語言中編譯器設計的乙個基本問題。它的實現借助於棧的「後進先出」特性。
乙個算術表示式是由運算元(運算物件)、運算子和分解符(括號)組成的有意義的式子。運算子從運算物件的個數上分為單目運算子和雙目運算子;從運算型別上可以分為算術運算子、關係運算子、邏輯運算子等,在此為了簡化問題考慮,我們假設算術運算子只包含加,減,乘,除雙目運算子和左右兩種圓括號。例如:
a-(b+c*d)/e
這種算術表示式中的運算子總出現在兩個運算元之間,這種算術表示式稱為中綴表示式。計算機編譯系統在計算乙個算術表示式之前要將中綴表示式轉換為字尾表示式,然後對字尾表示式進行計算。字尾表示式就是算術運算子出現在運算元之後,並且不含括號。在計算機中求解算術表示式的值分為兩個步驟:
(1)將中綴表示式轉換為字尾表示式
(2)依據字尾表示式計算表示式的值
1.將中綴表示式轉換為字尾表示式
要將乙個中綴表示式轉換為字尾表示式,首先要了解算術四則運算的規則。算術的四則運算的規則是:
(1)算術表示式的優先順序:先乘除,後加減;
(2)有括號的先算括號裡的,後算括號外的,多層括號的由內到外進行;
(3)同級別的從左到右進行計算;
上面的算術表示式轉換為字尾表示式為:
a b c d * + e / -
不難看出字尾表示式具有以下3個特點:
(1)字尾表示式與中綴表示式的運算元出現順序相同,只是運算子先後順序改變了;
(2)字尾表示式不出現括號;
(3)字尾表示式的操作符出現在運算元之後。
字尾表示式也叫作逆波蘭表示式,是波蘭邏輯學家jan.lukasiewicz於2023年提出的表示方法。每個運算子都位於運算元之後,故稱為字尾表示。字尾表示式既無括號也無優先順序的約束,因此只需要從左到右依次掃瞄字尾表示式的各個字元,遇到運算子時,直接對運算子前面兩個運算元進行運算即可。
如何將中綴表示式轉換為字尾表示式呢?可以設定乙個棧,用於存放運算子。依次讀入表示式中的每個字元,如果是運算元直接輸出。如果是運算子,則比較棧頂元素符與當前運算子的優先順序,然後進行處理,直到整個表示式處理完畢。我們約定『#』作為字尾表示式的結束標誌,假設θ1為棧運算子,θ2為當前掃瞄的運算子。則中綴表示式轉換為字尾表示式的演算法描述如下:
(1)初始化棧,並將『#』入棧;
(2)若當前字元是運算元,則將該運算元輸出,並讀入下一字元;
(3)若當前字元是運算子,記作θ2,將θ2與棧頂的運算子θ1比較。若θ1優先順序低於θ2,則將θ2進棧;若θ1優先順序高於θ2,則將θ1出棧並將其作為字尾表示式輸出。然後繼續比較新的棧頂運算子θ1和與當前運算子θ2的優先順序,若θ1的優先順序與θ2相等,且θ1為『(』,θ2為『)』,則將θ1出棧,繼續讀入下乙個字元;
(4)如果θ2的優先順序與θ1相等,且θ1和θ2都為『#』,將θ1出棧,棧為空。則完成中綴表示式轉換為字尾表示式,演算法結束。
運算子的優先順序關係如表所示:
利用上述演算法,將中綴表示式a-(b+c*d)/e轉換為字尾表示式的輸出過程如下表(為了便與描述,在表示式末尾加乙個結束標誌『#』)
2.字尾表示式的計算
在計算字尾表示式時,需要設定兩個棧:operator棧和openand棧。其中operator棧用於存放運算子,operand用於存放運算元和中間運算結果。具體運算思想如下:依次讀入字尾表示式中的每個字元,如果是運算元,則將運算元進入operand棧。如果是運算子,則將運算元出棧兩次,然後對運算元進行當前操作符的運算。直到整個表示式處理完畢。
linkstack.h
#pragma once
#include #include using namespace std;
typedef char datatype;
typedef struct node
lstacknode,*linkstack;
void initstack(linkstack *top)
(*top)->next = null;
}int stackempty(linkstack top)
else }
int pushstack(linkstack top, datatype e)
p->data = e;
p->next = top->next;
top->next = p;
return 1;
}int popstack(linkstack top, datatype *e)
top->next = p->next;
*e = p->data;
free(p);
return 1;
}int gettop(linkstack top, datatype *e)
*e = p->data;
return 1;
}int stacklength(linkstack top)
return count;
}void destorystack(linkstack top)
}
main.cpp
#include #include #include #include #include "linkstack.h"
#define maxsize 50
typedef struct
opstack;
void translateexpress(char s1,char s2);
float computeexpress(char s);
void main()
float computeexpress(char a)
s.top++;
s.data[s.top] = value;
} else
i++;
} }if (!s.top!=-1)
else
}}void translateexpress(char str, char exp)
popstack(s, &e);
break;
case '+':
case '-':
while (!stackempty(s)&&gettop(s,&e)&&e!='(')
pushstack(s, ch);
break;
case '*':
case '/':
while (!stackempty(s)&&gettop(s,&e)&&e=='/'||e=='*')
pushstack(s, ch);
break;
default:
while (ch>='0'&&ch<='9')
i--;
exp[j] = ' ';
j++;
/*break;*/
} ch = str[i];
i++;
} while (!stackempty(s))
exp[j] = '\0';
}
結果:
鏈式表示的棧 鏈式棧2 進製轉換
利用鍊錶模擬棧實現十進位制數2015轉換為對應的八進位制數。分析 一般情況下,把十進位制轉換為八進位制 二進位制等可以使用輾轉相除法,例如將十進位制數2015轉換為八進位制數的過程如圖。轉換後的八進位制數為 3737 在圖中,被除數除以8得到商數,記下餘數,又將商數作為新的被除數繼續除以8,直到商為...
棧的鏈式儲存表示
typedef struct stack node elemtype data struct stack node next stack node 1 棧的初始化 stack node init link stack void stack node top top stack node malloc...
棧 算術表示式
將乙個算術表示式 即中綴形式 轉化成其字尾形式,並算出答案。include include include include include include using namespace std using namespace std bool isoperator char ch return f...