題前需要了解的:中綴、后綴表達式是什么?(不知道你們知不知道,反正我當時不知道,搜的百度)
基本思路:先把輸入的中綴表達式→后綴表達式→進行計算得出結果
棧:”先進先出,先進后出“!
-
中綴轉后綴(先把轉換后的后綴表達式存入字符數組):從左至右依次讀取,遇到運算數存入字符數組,遇到運算符壓入棧,繼續讀取–如果遇到的運算符優先級比棧頂的運算符優先級低或者相等(比如“+與+或-” ----- “* 與 或/”------“/與/或”),則先將棧中的運算符輸送至字符數組(如果棧中有“(”,則只輸出到左括號就停止輸出,不輸出左括號),繼續讀取–如果遇到運算符優先級比棧頂運算符高的則入棧成為新的棧頂運算符,繼續讀取----如果遇到“)”,則將棧元素輸出至字符數組,直至輸出至”(“停止(在后綴表達式中沒有括號,所以括號不輸出入字符數組),直至讀取完畢,然后將棧中剩余的運算符輸出至字符數組。完畢!(注意:在遇到右括號”)“后就要將”(“左括號從棧中刪除了,因為為防止將括號輸出至字符數組)。
-
后綴表達式求值:從左至右讀取,遇到運算數則將其存入棧中,遇到運算符(比如”/“)則將棧頂元素的前一個運算數(比如temp1)與棧頂元素(比如temp2)出棧(–注意–)並進行運算,temp1/temp2,並將其最終結果重新壓入棧中成為新的棧頂元素,直至得出最終結果。
上代碼:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 100
typedef float Num;//為防止以后變換操作數類型需要
typedef struct
{
Num data[MAX];
int top;
}StackNum;//運算數棧
typedef struct
{
char data[MAX];
int top;
}StackChar;//運算符棧
//------函數聲明---------
void InitNum(StackNum *p);//運算數棧初始化
void PushNum(StackNum *p, Num e);//運算數壓棧
void PopNum(StackNum *p, Num *e);//運算數出棧
Num GetNum(StackNum p);//取棧頂元素
//-----------------------
void InitChar(StackChar *p);//運算符棧初始化
void PushChar(StackChar *p, char e);//運算符壓棧
void PopChar(StackChar *p, char *e);//運算符出棧
//-----------------------
void Fun(StackNum *p, char e);//計算並壓入運算數棧
//-----------------------
void main()
{
int i;//循環變量
Num temp;//存放一個臨時轉換數
char str[MAX], ch;//存放中綴表達式原式,臨時運算符
//-----------
StackNum n1;
StackChar c1;
InitNum(&n1);
InitChar(&c1);
//------------
for (;;)
{
printf("請輸入中綴表達式:");
gets(str);
/* 注意字符串輸入函數與scanf("%s",str) 的區別,scanf遇到空白字符, 包括空格,制表符,換行符時均會停止輸入,所以不可取,而gets功能為讀入一行, 並將換行符轉換為字符串結束符。 */
for (i = 0; str[i] != '\0'; i++)//讀完整字符串-----字符串結束標志'\0'
{
if (str[i] >= '0'&&str[i] <= '9')//分岔點一:----------------------------------------------------------------如果為數字
{
temp = str[i] - '0';//-----將字符轉換為數值
while (str[i + 1] != '\0')//多位數值獲取
{
if (str[i + 1] >= '0'&&str[i + 1] <= '9')
{
temp = temp * 10 + str[i + 1] - '0';//------注意!
i++;
}
else
break;//如果不是多位數字,則跳出多位獲取循環
}
PushNum(&n1, temp);//將獲取來的數值入棧
}
else if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' || str[i] == '(' || str[i] == ')')//分岔點二:-------如果為運算符
{
switch (str[i])//表達式可為:整型/字符型/枚舉型-----C語言中
{
//case 后可為 整型,字符型----C語言中
case '+':
if (c1.data[c1.top - 1] != '+'&&c1.data[c1.top - 1] != '-'&&c1.data[c1.top - 1] != '*'&&c1.data[c1.top - 1] != '/')
{
PushChar(&c1, '+');
}
else//如果不然,則將之前的先都出棧並計算,然后再入棧
{
while (c1.top > 0 && c1.data[c1.top - 1] != '(')//將優先級高的運算符先輸出計算,其中括號內的優先級最高
{
PopChar(&c1, &ch);
Fun(&n1, ch);//計算,並壓運算數棧
}
PushChar(&c1,'+');
}
; break;
case '-':
if (c1.data[c1.top - 1] != '+'&&c1.data[c1.top - 1] != '-'&&c1.data[c1.top - 1] != '*'&&c1.data[c1.top - 1] != '/')
{
PushChar(&c1, '-');
}
else//如果不然,則將之前的先都出棧並計算,然后再入棧
{
while (c1.top > 0 && c1.data[c1.top - 1] != '(')//將優先級高的運算符先輸出計算,其中括號內的優先級最高
{
PopChar(&c1, &ch);
Fun(&n1, ch);//計算,並壓運算數棧
}
PushChar(&c1, '-');
}
; break;
case '*':
if (c1.data[c1.top - 1] != '*'&&c1.data[c1.top - 1] != '/')
{
PushChar(&c1, '*');
}
else//如果不然,則將之前的先都出棧並計算,然后再入棧
{
while (c1.top > 0 && c1.data[c1.top - 1] != '(')//將優先級高的運算符先輸出計算,其中括號內的優先級最高
{
PopChar(&c1, &ch);
Fun(&n1, ch);//計算,並壓運算數棧
}
PushChar(&c1, '*');
}
; break;
case '/':
if (c1.data[c1.top - 1] != '*'&&c1.data[c1.top - 1] != '/')
{
PushChar(&c1, '/');
}
else//如果不然,則將之前的先都出棧並計算,然后再入棧
{
while (c1.top > 0 && c1.data[c1.top - 1] != '(')//將優先級高的運算符先輸出計算,其中括號內的優先級最高
{
PopChar(&c1, &ch);
Fun(&n1, ch);//計算,並壓運算數棧
}
PushChar(&c1, '/');
}
; break;
case '(':
PushChar(&c1, '(');
; break;
case ')'://並沒有將'('壓入棧中,只是當作一種出棧信號
while (c1.data[c1.top - 1] != '(')
{
PopChar(&c1, &ch);
Fun(&n1, ch);//計算,並壓運算數棧
}
PopChar(&c1, &ch);//將'('也出棧,但並不計算
; break;
}
}
}
while (c1.top > 0)//將剩余的運算符出棧並計算
{
PopChar(&c1, &ch);
Fun(&n1, ch);
}
printf("\t\t%s=%.2f", str, GetNum(n1));
printf("\n");
system("pause");
}
}
void InitNum(StackNum *p)
{
p->top = 0;
}
void InitChar(StackChar *p)
{
p->top = 0;
}
void PushNum(StackNum *p, Num e)
{
if (p->top == MAX)
printf("運算數棧滿!\n");
else
{
p->data[p->top] = e;
p->top++;
}
}
void PushChar(StackChar *p, char e)
{
if (p->top == MAX)
printf("運算符棧滿!\n");
else
{
p->data[p->top] = e;
p->top++;
}
}
void PopNum(StackNum *p, Num *e)
{
if (p->top == 0)
printf("運算數棧空!\n");
else
{
p->top--;
*e = p->data[p->top];
}
}
void PopChar(StackChar *p, char *e)
{
if (p->top == 0)
printf("運算符棧空!\n");
else
{
p->top--;
*e = p->data[p->top];
}
}
void Fun(StackNum *p, char e)
{
Num temp1, temp2;//存放兩個臨時操作數
PopNum(p, &temp2);
PopNum(p, &temp1);
switch (e)
{
case '+':PushNum(p, temp1 + temp2); break;
case '-':PushNum(p, temp1 - temp2); break;
case '*':PushNum(p, temp1*temp2); break;
case '/':PushNum(p, temp1 / temp2); break;
}
}
Num GetNum(StackNum p)
{
return p.data[p.top - 1];
}
因為我也是個小菜鳥,所以本次也全當作筆記總結的文章,我又找了兩篇我參考的大佬的文章,如下:
原文:https://blog.csdn.net/myCsdn_Xm/article/details/80861183
后綴表達式的求值(c語言)
題目描述
為了便於處理表達式,常常將普通表達式(稱為中綴表示)轉換為后綴{運算符在后,如X/Y寫為XY/表達式。在這樣的表示中可以不用括號即可確定求值的順序,如:(P+Q)(R-S) → PQ+RS-。后綴表達式的處理過程如下:掃描后綴表達式,凡遇操作數則將之壓進堆棧,遇運算符則從堆棧中彈出兩個操作數進行該運算,將運算結果壓棧,然后繼續掃描,直到后綴表達式被掃描完畢為止,此時棧底元素即為該后綴表達式的值。
輸入
輸入一行表示后綴表達式,數與數之間一定有空格隔開(可能不只一個空格),最后輸入@表示輸入結束。
數據保證每一步的計算結果均為不超過100000的整數。
輸出
輸出一個整數,表示該表達式的值.
樣例輸入
14 3 20 5 / *8 - + @
樣例輸出
18
#include<stdio.h>
typedef struct STRACK //定義結構體
{
double a[100];
int top;
} STRACK;
int main()
{
double totle=0,e=0;
char s[100];
int i;
STRACK L;
L.top=-1;
gets(s);
for(i=0; s[i]!='@'; i++)
{
if(s[i]<='9'&&s[i]>='0')
{
L.top++;
int temp=s[i]-'0';
int k=i+1;
while(s[k]!='@') //利用while循環得到由多位由字符組成的數值
{
if(s[k]<='9'&&s[k]>='0')
{
temp=10*temp+(s[k]-'0');
i++;
k++;
}
else break;
}
L.a[L.top]=temp;
}
else if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/') //遇到運算符進行計算
{
switch(s[i])
{
case '+':
e=L.a[L.top-1]+L.a[L.top];
break;
case '-':
e=L.a[L.top-1]-L.a[L.top];
break;
case '*':
e=L.a[L.top-1]*L.a[L.top];
break;
case '/':
e=L.a[L.top-1]/L.a[L.top];
break;
}
L.a[L.top-1]=e; //往前一位存儲
L.a[L.top]=0;
L.top--;
}
}
printf("%.0lf",L.a[L.top]); //輸出最后結果
return 0;
}
原文:https://blog.csdn.net/hanmiaobei7428/article/details/82049881
中綴表達式的求值問題
表達式的求值問題(堆棧)
0. 解決目標
將形如2*(9+6/3-5)+4表達式求值的思想
- 后綴表達式的求值
形如這里寫圖片描述的表達式如何求值?
(翻譯成中綴表達式為:6/2-3+4*2,我們不進行中綴表達式的翻譯操作,只是為了方便理解中間的過程)
從左向右“掃描”,逐個處理運算數和運算符號
遇到運算數怎么辦?如何“記住”目前還不未參與運算的數?
遇到運算符號怎么辦?對應的運算數是什么?
下圖是一種解決辦法。
這里使用一種結構,由於長得像先稱之為“槽”,這種槽有什么特點?
1.只能存放數字
2.存放的數字只能后面進來的先出
這里有個問題,如果是符號怎么辦呢?
我們提供一種解決辦法,如果遇到符號,則將槽最頂部的數字與前一個數字從槽中拿出,進行操作,操作為:
1.前一個數字 運算符 槽最頂部的數字
2.並講運算結果 再放入槽中
3.直至所有東西都按從左到右的順序 嘗試進入槽中,便得到結果。
這種能夠解決后綴表達式的求值問題的結構——“槽”,就是堆棧。它是一種線性存儲結構,后入先出。
我們用堆棧解決了后綴表達式的求值問題,那么問題來了,如何將中綴表達式轉換成后綴表達式呢?
##2. 中綴化后綴
目標:將形如2*(6/3+4)-5的中綴表達式化成 2 6 3 / 4 + * 5 -的后綴表達式
帶括號的表達式看起來比較復雜,我們先看沒有括號的轉換。
小目標:將形如2+9/3-5的中綴表達式化成2 9 3 / + 5 - 的后綴表達式
構造一種堆棧,只能存放符號,同樣遵循后入先出的原則。
有兩個問題
1.遇到數字怎么辦?
2.堆棧中的符號怎么處理?
第一個問題很簡單,輸出即可,因為我們只需要求表達式,並不需要同時計算。
第二個問題,因為符號有優先級,當將符號放入堆棧時,比較其與前一個符號的優先級,若低於,則先輸出前一個運算符。這個也很好理解,高優先級的運算先進行。
解決過程如下圖所示。
那如果帶括號要怎么解決呢?問題有:
1.括號也算一種符號,但括號不參與運算,
2.括號提供一種優先級,括號里面的運算優先級最高
第一個問題,我們在后綴表達式轉換成值的時候是直接進行操作的,利用順序已經將括號的功能包括進去,但只是不顯示括號而已。具體解決是在一對括號齊全時,將其中的運算符輸出。
第二個問題,我么將括號放入堆棧之前認為其優先級最高,在放入堆棧之后,將其認為優先級最低,即只進行括號里面的優先級比較(忽略括號)。
解決過程如下圖。
總結中綴表達式轉化成后綴表達式的方法如下:
按照 步驟2->1->0 完成目標
學習自《數據結構:陳越》之線性結構
呼,終於把最近看的,學的,總結起來了。。。
我如果有什么地方弄得不對的,看到的道友可以在下方評論說出來,或者私信我。
學習使我們快樂~