將算數表示式轉換成字尾表示式並計算結果
背景
用計算機實現帶括號的四則運算的方式。這裡的困難在於乘除運算的優先順序高於加減運算,並且加入了括號,使得問題變得更加困難。20世紀50年代,波蘭邏輯學家想到了一種不需要括號的字尾表達法,我們也把它稱為逆波蘭表示。比如:9+(3-1)*3+10/2
,如果用字尾表示法就是9 3 1 - 3 * + 10 2 / +
,這樣的表示式稱為字尾表示式,叫字尾的原因在於所有的符號都是要在運算數字的後面出現。
假設算數表示式只包含“+”、“-”、“×”、“÷”、正整數和括號的合法數學表示式,這稱為簡單算數表示式。對該表示式求值的過程是:先將算數表示式轉換成字尾表示式(亦稱為逆波蘭表示式),然後對該字尾表示式求值。
為什麼要這樣做呢?人可以通過看一眼就知道先乘除後加減進行計算,但是計算機不可以。如果轉換成字尾表示式,就已經把運算次序考慮過了,計算機在進行運算的時候就不需要考慮運算的次序。
建議
本篇部落格大概有170行程式碼,如果逐行閱讀,會有一種雲裡霧裡的感覺,建議先去體會如何利用字尾表示式求值,可以在演草紙上寫寫畫畫,理解了使用字尾表示式相對算數表示式(中綴表示式)的好處之後,再仔細揣摩字尾表示式是如何得到的。程式碼量一旦增加,閱讀他人的程式碼,就要由頂至下去閱讀,逐行閱讀費時費力,而且不是很簡單讀懂他人的程式碼。
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100
巨集定義NUL為字串結束符:
#define NUL '\0'
運算子棧用於存放字尾表示式(重點):
/*運算子棧型別*/
typedef struct
{
char data[MaxSize];
int top;
}OP;
數值棧用於存放數值:
/*數值棧型別*/
typedef struct
{
float data[MaxSize];
int top;
}ST;
trans函式編寫思路如下:遍歷字串exp
- 字元ch為數字,將後繼所有數字字元均依次存放到postexp中,並以字元"#"標誌數字串的結束
- 字元ch為左括號"(",將此括號進棧到運算子棧op中
- 字元ch為右括號")",將運算子棧op中左括號"("以前的運算子依次出棧,並將左括號刪除
- 字元ch的運算子優先順序不大於運算子棧op的棧頂運算子(除了棧頂運算子為左括號“(”外)的優先順序,則依次出棧並存入到postexp中,然後將字元ch進棧
- exp掃描完畢,將運算子棧op中所有的運算子依次出棧並存放到postexp中,得到字尾表示式postexp
/*****************************************************************
*函式名:trans
*函式功能描述:將中綴表示式exp轉化為字尾表示式postexp(也稱逆波蘭表示式)
*函式引數:exp[]-存放中綴表示式的字元陣列,postexp[]-存放字尾表示式的字元陣列
*函式返回值:無返回值
*作者:王賦睿
*函式建立日期:2018.5.27
*函式修改日期:尚未修改
*修改人:尚未修改
*修改原因:尚未修改
*版本:1.0
*歷史版本:無
*****************************************************************/
void trans(char exp[], char postexp[])
{
char ch;
int i = 0, j = 0;
OP op;
op.top = -1;//初始化運算子棧
ch = exp[i]; i++;
while (ch != NUL)
{
switch (ch)
{
case '(':
op.top++;
op.data[op.top] = ch;
break;
case ')':
while (op.data[op.top] != '(')
{
postexp[j++] = op.data[op.top--];
}
op.top--;
break;
case '+':
case '-':
while (op.top != -1 && op.data[op.top] != '(')
{
postexp[j++] = op.data[op.top--];
}
op.top++; op.data[op.top] = ch;
break;
case '*':
case '/':
while (op.top != -1 && op.data[op.top] != '(' && (op.data[op.top] == '*' || op.data[op.top] == '/'))
{
postexp[j++] = op.data[op.top--];
}
op.top++;
op.data[op.top] = ch;
break;
case ' ':
break;//過濾掉空格
default:
while (ch >= '0'&&ch <= '9')
{
postexp[j++] = ch;
ch = exp[i++];
}
i--;
postexp[j++] = '#';
break;
}
ch = exp[i++];
}
while (op.top != -1)
{
postexp[j++] = op.data[op.top--];
}
postexp[j] = NUL;
}
針對字尾表示式進行求值:遍歷字尾表示式postexp:
- 字元ch為數字,將後繼的所有數字字元構成一個整數存放到數值棧st中
- 字元ch為"+"或"-",則從數值棧st中退棧兩個運算數,相加(減)後進棧數值棧st中
- 字元ch為"×",則從數值棧st中退棧兩個運算數,相乘後進棧數值棧st中
- 字元ch為"÷",則從數值棧退棧兩個運算數,相除後進棧st中(若除數為0,則提示錯誤)
/*****************************************************************
*函式名:compvalue
*函式功能描述:字尾表示式postexp(也稱逆波蘭表示式)的值計算出來
*函式引數:postexp[]-存放字尾表示式的字元陣列
*函式返回值:返回值是計算出來的值
*作者:王賦睿
*函式建立日期:2018.5.27
*函式修改日期:尚未修改
*修改人:尚未修改
*修改原因:尚未修改
*版本:1.0
*歷史版本:無
*****************************************************************/
float compvalue(char postexp[])
{
float d=0;
char ch;
int i = 0;
ST st;
st.top = -1;
ch = postexp[i++];
while (ch != NUL)
{
switch (ch)
{
case '+': //從數值棧st退棧兩個運算數,相加後進入數值棧st中
st.data[st.top - 1] += st.data[st.top];
st.top--;
break;
case '-': //從數值棧st退棧兩個運算數,相減後進入數值棧st中
st.data[st.top - 1] -= st.data[st.top];
st.top--;
break;
case '*': //從數值棧st退棧兩個運算數,相乘後進入數值棧st中
st.data[st.top - 1] *= st.data[st.top];
st.top--;
break;
case '/': //從數值棧st退棧兩個運算數,相除後進入數值棧st中
if (st.data[st.top] != 0)
st.data[st.top - 1] /= st.data[st.top];
else
{
printf("\n\t除零錯誤!\n");
exit(0);
}
st.top--;
break;
default:
d = 0; //將數字字元轉換成對應的數值存放在d中
while (ch >= '0'&&ch <= '9') //判定為數字字元
{
d = 10 * d + ch - '0';
ch = postexp[i++];
}
st.top++;
st.data[st.top] = d;
break;
}
ch = postexp[i++];
}
return st.data[st.top];
}
進行測試用例:
int main()
{
char exp[MaxSize] = { "15*66-89*13+10" };
char postexp[MaxSize];
trans(exp, postexp);
float d = compvalue(postexp);
printf("%f", d);
return 0;
}
本程式在VS2017下執行通過
相關文章
- 【資料結構與演算法】中綴表示式轉字尾表示式以及字尾表示式的計算資料結構演算法
- 中綴表示式轉化為字尾表示式並求值
- 中綴表示式轉字尾表示式
- C#字尾表示式解析計算字串公式C#字串公式
- js實現四則計算(中綴,字尾表示式)JS
- 逆波蘭演算法、中綴表示式轉字尾表示式演算法
- 資料結構與演算法——棧(五)中綴表示式轉字尾表示式資料結構演算法
- 前中字尾表示式
- 計算中綴表示式
- 一個數學表示式的計算
- C#資料結構與演算法系列(十):逆波蘭計算器——逆波蘭表示式(字尾表示式)C#資料結構演算法
- 教你如何在C++中實現中綴表示式轉字尾表示式C++
- 使用棧結構計算中綴表示式
- 棧的應用---字尾表示式
- 表示式計算(棧的應用)
- 算數表示式求值--c語言課程設計C語言
- 字首中綴字尾表示式規則
- C/C++ 陣列連結串列表示式計算C++陣列
- 計算機組成與體系結構-數值表示範圍-浮點數計算計算機
- 2. 計算機怎麼表示數字計算機
- 【棧】【字串語法】牛牛與字尾表示式字串
- [藍橋杯 2019 省 B] 字尾表示式
- 計算機組成與體系結構-浮點數表示計算機
- 中綴轉字尾表示式思路分析和程式碼實現
- 正規表示式中 “$” 並不是表示 “字串結束字串
- C語言- 基礎資料結構和演算法 - 09 棧的應用_中綴表示式轉字尾表示式20220611C語言資料結構演算法
- 百行以內實現複雜數學表示式計算
- 【正規表示式】常用的正規表示式(數字,漢字,字串,金額等的正規表示式)字串
- Python 如何傳遞運算表示式Python
- 藍橋杯2019年真題:字尾表示式
- android 將字串轉成算術表示式Android字串
- 【計算機演算法】 求字首表示式的值計算機演算法
- 使用棧實現表示式求值,運用棧計算
- leetcode 224. 基本計算器(逆波蘭表示式)LeetCode
- c++虛擬函式實現計算表示式子C++函式
- 匹配純數字正規表示式
- 中綴表示式轉為逆波蘭表示式
- 將Lucene搜尋查詢轉換為.NET的EF表示式