本文內容:C語言實現並附有相關講解
- 計算中綴表達式
- 計算後綴表達式
- 計算前綴表達式
- 中綴轉後綴表達式
- 中綴轉前綴表達式
相關鏈接:
【例子】
表達式 | 例子 |
---|---|
表達式(中綴) | |
前綴 | |
後綴 |
【計算結果】
【代碼】
#include<stdio.h>
#include<string.h>
// 計算
float Cal(float a, char op, float b) {
switch (op) {
case '+' : return (a+b);
case '-' : return (a-b);
case '*' : return (a*b);
case '/' : return (a/b);
}
return 0;
}
/*-----------------------
|計算中綴表達式 |
-----------------------*/
/*
數據結構:兩個棧,一個存放操作數(stack1),一個存放運算符(stack2)
操作步驟:
1. 從左到右掃描中綴表達式
若是數字,直接入stack1
若是字符:
若運算符棧爲空,直接入棧stack2
若棧不爲空,則要與stack2的棧頂的優先級進行比較
若當前字符爲左括號,則壓入stack2棧中
若當前字符爲右括號,則從stack2中取出運算符,再從stack1棧中取出兩個數字進行運算,運算結果壓入stack1中;直到棧頂元素爲左括號,將左括號彈出即可(即右括號與左括號做抵消)
若當前字符的優先級小於棧頂,則將棧頂元素拋出,從操作數棧中取兩個數字進行運算,運算結果壓入操作數棧。繼續判斷此字符與棧頂元素優先級大小,直到棧頂元素優先級小於此字符
若當前字符的優先級大於棧頂,則將此字符直接壓入運算符棧中
2. 最後,若棧中還有元素,取出繼續計算
函數:
1. CalInfix(str[]):傳入中綴表達式,返回計算結果
2. Cal_from_stack12:上述步驟中,重複的操作即是從stack1中取操作數,stack2中取運算符進行運算,最後將結果壓入stack1中。因此將這些操作封裝成函數簡化代碼,增加可讀性
*/
float Cal_from_stack12(float stack1[], int &top1, char stack2[], int &top2) {
// stack1爲數字的棧、stack2爲運算符的棧
// 從兩個棧中計算
char op = stack2[top2--];
float b = stack1[top1--];
float a = stack1[top1--];
float ret = Cal(a, op, b);
stack1[++top1] = ret;
return ret;
}
float CalInfix(char str[]) { //計算中綴表達式
float stack1[100]; int top1=-1; //存放數字的棧
char stack2[100]; int top2=-1; //存放運算符的棧
int i;
// 遍歷中綴表達式
for (i=0; str[i]!='\0'; ++i) {
// str[i]是數字,直接入棧,後退出此次循環
if (str[i]<='9' && str[i]>='0') { // str[i]數字
stack1[++top1]=(float)(str[i]-'0');
continue;
}
//str[i]是字符(運算符)
// 運算符的棧爲空,直接入棧
if (top2==-1) {
stack2[++top2] = str[i];
continue;
}
// 運算符的棧不爲空,要比較和棧頂的優先級
if (str[i]=='+' || str[i]=='-') { // 當前運算符爲+、-,那麼比+、-、*、/優先級都小,所以要讓它們都先計算完才能入棧
while (stack2[top2]=='+' || stack2[top2]=='-' || stack2[top2]=='*' || stack2[top2]=='/') {
Cal_from_stack12(stack1, top1, stack2, top2); //計算
}
stack2[++top2]=str[i]; //運算完後,str[i]入棧
} else if (str[i]=='*' || str[i]=='/') { // 只有*、/計算完後,才能入棧
while (stack2[top2]=='*' || stack2[top2]=='/') {
Cal_from_stack12(stack1, top1, stack2, top2); //計算
}
stack2[++top2]=str[i]; //運算完後,str[i]入棧
} else if (str[i]=='(') { //左括號,直接入棧
stack2[++top2]=str[i];
} else if (str[i]==')') { //右括號,處理到把'('抵消
while (stack2[top2]!='(') {
Cal_from_stack12(stack1, top1, stack2, top2); //計算
}
top2--; //彈出左括號
}
}
// 遍歷完成後,檢查棧是否計算完
while (top2!=-1) {
Cal_from_stack12(stack1, top1, stack2, top2); //計算
}
return stack1[top1]; //返回計算結果
}
/*-------------------------
|中綴表達式 轉 前綴表達式|
-------------------------*/
/*
數據結構:
1. 一個棧stack:用於存運算符
2. 一個數組tmp:用於暫時存儲輸出結果,這個結果實際是前綴表達式的逆序。即結束後,將此數組逆置就獲得了前綴表達式
算法步驟:從右至左掃描中綴表達式
若是操作數,直接輸出到tmp數組中
若是運算符,查看棧頂
若是右括號,直接壓入棧中
若是左括號,將棧元素彈出輸出到tmp數組中,直到抵消到棧中的右括號
若此運算符優先級小於棧頂元素,則棧內元素出棧並輸出到tmp數組中,直到該運算符優先級大於等於棧頂元素,再將其壓入棧中
否則,則該運算符直接入棧
最後將棧中剩餘元素輸出到tmp中,結束後,將tmp數組翻轉
*/
int infix_to_prefix(char in[], char pre[]) {
char stack[100]; int top=-1; //用於存放運算符
char tmp[100]; int j=0; //存放暫時的結果,即前綴表達式的逆序
int i;
for (i=strlen(in)-1; i>=0; --i) { //從右到左掃描中綴表達式
if ('0' <= in[i] && in[i] <= '9') { //操作數,直接輸出
tmp[j++] = in[i];
} else if (in[i]==')') {
stack[++top] = in[i];
} else if (in[i]=='(') {
while (stack[top]!=')') {
tmp[j++] = stack[top--];
}
--top; //左括號出棧
} else if (in[i]=='+' || in[i]=='-') {
while (stack[top]=='*' || stack[top]=='/') {
tmp[j++] = stack[top--];
}
stack[++top] = in[i];
} else if (in[i]=='*' || in[i]=='/') {
stack[++top] = in[i];
} else {
return 0;
}
}
// 輸出剩餘東西
while (top!=-1) {
tmp[j++] = stack[top--];
}
// 逆置
i=0;
for (i=0, j=j-1; j>=0; ++i,--j) {
pre[i] = tmp[j];
}
pre[i]='\0';
return 0;
}
/*-----------------------
|計算前綴表達式:波蘭式|
-----------------------*/
/*從左到右遍歷前綴表達式
若遇到操作符,入棧
若遇到操作數,查看棧頂
若棧頂是操作符,入棧;
若棧頂是操作數,則將操作數出棧,再出棧一個操作符,進行運算,運算後繼續判斷棧頂情況,直到棧頂不是操作數或棧空再將結果入棧
*/
typedef struct{
union{
char op;
float num;
}data;
int flag; //0爲操作數,1爲num
}StackNode; //棧的結點
float CalPrefix(char str[]) {
// 默認:前綴表達式合法
StackNode stack[100]; int top=-1; //用於存放操作數和操作符的棧
char op;
float a,result;
int i;
for (i=0; str[i]!='\0'; ++i) {
if ('0' <= str[i] && str[i] <='9') { //數字
if ( top==-1 || stack[top].flag!=1 ) { // 棧頂爲空 或 棧頂不是數字,直接入棧
++top; stack[top].flag=1; stack[top].data.num = (float)(str[i]-'0'); //數字入棧
continue; //此次循環處理結束!
}
result = (float)(str[i]-'0'); //獲得當前的數字
while (top!=-1 && stack[top].flag==1) { // 棧頂如果是數字,一直判斷到不是數字
a = stack[top--].data.num; //在棧中取一個操作數
op = stack[top--].data.op; //在棧中取一個運算符
result = Cal(a, op, result); //計算
}
++top; stack[top].flag=1; stack[top].data.num = result; //將此輪計算結果入棧
} else { //操作符
++top; stack[top].flag=0; stack[top].data.op = str[i];
}
}
return stack[top].data.num;
}
/*-------------------------
|中綴表達式 轉 後綴表達式|
-------------------------*/
int infix_to_suffix(char in[], char suf[]) {
char stack[100]; int top=-1; //運算符的棧
int i, j;
j=0; //suf[]的指針
for (i=0; in[i]!='\0'; ++i) { //遍歷in
// 是數字
if ('0' <= in[i] && in[i] <= '9') {
suf[j++] = in[i];
continue;
}
// 是符號
if (top==-1) { //棧爲空
stack[++top] = in[i];
continue;
}
// 棧不爲空
if (in[i]=='+' || in[i]=='-') {
while (stack[top]=='+' || stack[top]=='-' || stack[top]=='*' || stack[top]=='/') {
suf[j++] = stack[top--];
}
stack[++top] = in[i];
} else if (in[i]=='*' || in[i]=='/') {
while (stack[top]=='*' || stack[top]=='/') {
suf[j++] = stack[top--];
}
stack[++top] = in[i];
} else if (in[i]=='(') {
stack[++top] = in[i];
} else if (in[i]==')') {
while (stack[top]!='(') {
suf[j++] = stack[top--];
}
top--; //將棧中'('輸出
} else {
suf[0]='\0';
return -1;
}
}
// 輸出剩下的符號
while (top!=-1) {
suf[j++] = stack[top--];
}
suf[j]='\0';
return 1; //轉換成功
}
/*-------------------------
|計算後綴表達式:逆波蘭式|
-------------------------*/
float CalSuffix(char str[]) {
float stack[100]; int top=-1; //存放數字
int i;
float a,b;
for (i=0; str[i]!='\0'; ++i) {
if ('0' <= str[i] && str[i] <= '9') { //數字
stack[++top]=(float)(str[i]-'0');
} else { //不是數字
b=stack[top--];
a=stack[top--];
stack[++top]=Cal(a, str[i], b);
}
}
return stack[top];
}
/* 例子
表達式(中綴):2*3+(7-6/5)*2
前綴: +*23*-7/652
後綴: 23*765/-2*+
測試數據:
2*3+(7-6/5)*2
(1+2*3)/(4/3+2)+4/2-2
*/
int main() {
char in[100], suf[100], pre[100];
for ( ; ; ) {
// 輸入中綴表達式
printf("請輸入中綴表達式:\n>>> ");
scanf("%s", in);
// CalInfix()函數測試
printf("[中綴表達式] %s\n", in);
printf("\t計算結果:%lf\n", CalInfix(in) );
// 前綴表達式
infix_to_prefix(in, pre);
printf("[前綴表達式] %s\n", pre);
printf("\t計算結果:%lf\n", CalPrefix(pre) );
// 後綴表達式
infix_to_suffix(in, suf);
printf("[後綴表達式] %s\n", suf);
printf("\t計算結果:%lf\n", CalSuffix(suf) );
printf("\n");
}
return 0;
}