演算法表示式求值演示(棧的應用)
阿新 • • 發佈:2018-12-16
【問題描述】 表示式計算是實現程式設計語言的基本問題之一,也是棧的應用的一個典型例子。設計一個程式,演示用算符優先法對算術表示式求值的過程。 【實現要求】 (1) 以字元序列的形式從終端輸入語法正確的、不含變數的整數表示式。利用下表給出的算符優先關係,實現對算術混合運算表示式的求值,並仿照求值中運算子棧、運算數棧、輸入字元和主要操作的變化過程。 (2) 擴充運算子集,如增加乘方、單目減、賦值等運算。 (3) 計算器的功能和模擬介面(選作)。 【測試資料】 下列表達式: 3*(7-2); 8; 1+2+3+4; 88-15; 1024/48; 1024/(48); (20+2)(6/2); 3-3-3; 8/(9-9); 2*(6+2*(3+6*(6+6))); (((6+6)*6+3)*2+6)*2; 【實現提示】
實現思路: 主要使用的是棧的結構。程式實現一共分為兩步:第一步,將輸入的表示式轉化為計算機方便處理的字尾表示式,;第二步,計算字尾表示式。 其中第一步,使用了兩個棧:操作符儲存棧(op)以及字尾表示式儲存棧(postexp)。而第二步,則是通過一個輔助棧,結合字尾表示式儲存棧(postexp)即主棧,分別對每個操作符以及對應得運算元進行計算,計算完成後再將其壓入主棧,最後當整個表示式計算完成後再將最後結果彈出,並輸出。 在處理單目操作符:“++”與“–”將其轉為“a”與“s”方便進行處理。 操作:
main.cpp
#include<iostream> #include<string> #include<stdlib.h> #include"stack.h" #include<Windows.h> using namespace std; char Precede(char a, char b) { int i, j; char pre[][10] = { /*運算子之間的優先順序製作成一張表格*/ { '>','>','<','<','<','>','<','<','<','>' }, { '>','>','<','<','<','>','<','<','<','>' }, { '>','>','>','>','<','>','<','<','<','>' }, { '>','>','>','>','<','>','<','<','<','>' }, { '<','<','<','<','<','>','<','<','<','0' }, { '>','>','>','>','0','=','>','>','>','>' }, { '>','>','>','>','<','>','>','<','<','>' }, { '>','>','>','>','<','>','>','>','>','>' }, { '>','>','>','>','<','>','>','>','>','>' }, { '<','<','<','<','<','0','<','<','<','=' } }; switch (a) { case '+': i = 0; break; case '-': i = 1; break; case '*': i = 2; break; case '/': i = 3; break; case '(': i = 4; break; case ')': i = 5; break; case '^': i = 6; break; case 'a': i = 7; break;//用a代替++符號方便處理 case 's': i = 8; break;//用s代替--符號方便處理 case '#': i = 9; break; } switch (b) { case '+': j = 0; break; case '-': j = 1; break; case '*': j = 2; break; case '/': j = 3; break; case '(': j = 4; break; case ')': j = 5; break; case '^': j = 6; break; case '++': j = 7; break; case '--': j = 8; break; case '#': j = 9; break; } return pre[i][j]; } int tranNum(stackL *postexp, string exp, int i)//將中綴表示式中的多位數,按照從低位到高位順序壓入postexp棧中,方便後續計算 { int len = 0,j; char expRead = exp[i]; while (expRead <= '9'&&expRead >= '0')//獲得數符長度 { //PushL(postexp, expRead); i++; expRead = exp[i]; len++; } for (j = i-1; j >= i - len;j--) { PushL(postexp, exp[j]); } i--; //使i恰好下次迴圈指向非數字 PushL(postexp, '#'); return i; } void tranPost(stackL *op, stackL*postexp, string exp)//將中綴表示式轉化為字尾表示式 { int i; char expRead, tempChar,preOp; InitStackL(op); InitStackL(postexp); PushL(op, '#'); PushL(postexp, '#'); for (i = 0; i < (int)exp.length(); i++) { expRead = exp[i]; if (expRead == '#') //表示式尾端 break; else if (expRead == ' ') //忽略空格 continue; else if (expRead <= '9'&&expRead >= '0') //處理運算元,傳入i,postexp,exp,返回i { i = tranNum(postexp, exp, i); } else if (expRead != '(' && expRead != ')' && expRead == exp[i + 1])//處理單目運算子(++、--) { if (expRead == '+') PushL(op, 'a'); else if (expRead == '-') PushL(op, 's'); else { cout << "error\n"; break; } i++; //使遍歷跳過自增自減符號到下一字元 } else //處理普通操作符 { tempChar = GetTopL(op); preOp = Precede(tempChar, expRead); if (expRead == ')') { tempChar = PopL(op); while (tempChar != '(') { PushL(postexp, tempChar); //PushL(postexp, '#'); tempChar = PopL(op); } } else if (preOp == '>') { PushL(postexp, PopL(op)); PushL(op, expRead); //PushL(postexp, '#'); } else if (preOp == '<') PushL(op, expRead); } } while (op->next->data != '#') { tempChar = PopL(op); PushL(postexp, tempChar); } } int ary(int expn) { int i; int sum = 1; for (i = 0; i < expn; i++) { sum *= 10; } return sum; } int getValue(stackL *assistStack)//求得屬於同一數值的連續數符的值 { int value = 0; int ex = 0; char charValue; charValue = PopL(assistStack); while (charValue != '#') { value += (charValue - 48)*ary(ex); ex++; charValue = PopL(assistStack); } return value; } void pushBack(stackL *postexp, int valueBack)//將計算出來的int值化作字元,並從低位到高位壓入主棧中 { int i = 0; char valueChar; if (valueBack == 0) PushL(postexp, '0'); while (valueBack != 0) { valueChar= (valueBack % 10)+48; PushL(postexp, valueChar); valueBack = valueBack / 10; } PushL(postexp, '#'); } int power(int value, int expn) { int result = 1; for (int i = 0; i < expn; i++) { result *= value; } return result; } int partCalu(stackL *postexp,stackL *assistStack )//計算小段式的值,此時兩個運算元分別在兩個棧中,運算元在輔助棧裡 { int value_1, value_2, value_3; char opera; PushL(assistStack, PopL(postexp)); while (GetTopL(postexp) <= '9'&&GetTopL(postexp) >= '0')//使兩個運算元和運算子都在輔助棧中,方便運算元的還原 { PushL(assistStack, PopL(postexp)); } value_1 = getValue(assistStack); value_2 = getValue(assistStack); opera = PopL(assistStack); switch (opera) { case '+': value_3 = value_1 + value_2; break; case '-': value_3 = value_1 - value_2; break; case '*': value_3 = value_1 * value_2; break; case '/': if (value_2 == 0) { cout << "error:除數為0" << endl; return 0; } else value_3 = value_1 / value_2; break; case'^': value_3 = power(value_1, value_2); default: break; } if (assistStack->next == NULL && postexp->next == NULL) { cout << value_2; return 0; } else if (assistStack->next == NULL && postexp->next->next == NULL)//結束條件 { cout << value_3; return 0; } pushBack(postexp, value_3);//將部分求值結果重新壓入主棧 if (GetTopL(assistStack) <= '9'&&GetTopL(assistStack) >= '0')//再次滿足部分求值條件 partCalu(postexp, assistStack); } int caluValue(stackL *postexp) { int control = 1; int value = 0; stackL *assistStack; char postRead,opera; assistStack = (stackL*)malloc(sizeof(stackL)); InitStackL(assistStack); postRead = GetTopL(postexp); while (postexp->next != NULL) { /*主棧棧頂為#時進行是否部分求值檢測, 如果輔助棧頂為數符的話,則進行部分求值,求值後將值繼續壓入主棧, 壓入時注意低位先壓入,這樣就可以在連續求值時進行遞迴*/ if (postRead == '#'&&assistStack->next!=NULL) { if (GetTopL(assistStack) <= '9'&&GetTopL(assistStack) >= '0') { control =partCalu(postexp, assistStack); if (control == 0) return 0; } else if(GetTopL(assistStack) > '9'|| GetTopL(assistStack) < '0') PushL(assistStack, PopL(postexp)); } else if (postRead == 'a'||postRead == 's') { opera=PopL(postexp); if (GetTopL(postexp) != '#') { cout << "單目運算子運用錯誤,應放在數字後" << endl; exit(0); } else { PushL(assistStack,PopL(postexp)); while (GetTopL(postexp) <= '9'&&GetTopL(postexp) >= '0')//將數符彈出主棧 並壓入輔助棧中 { PushL(assistStack, PopL(postexp)); } if (opera == 'a') pushBack(postexp, getValue(assistStack) + 1); else if (opera == 's') pushBack(postexp, getValue(assistStack) - 1); } } else PushL(assistStack, PopL(postexp)); postRead = GetTopL(postexp); } } int main() { while (1) { string express; cout << "please enter the expression statement,and end with '#'" << endl; cin >> express; stackL *op, *postexp; op = (stackL*)malloc(sizeof(stackL)); // 操作符棧 postexp = (stackL*)malloc(sizeof(stackL)); //字尾表示式棧 tranPost(op, postexp, express); //將輸入的中綴表示式轉化為字尾表示式 cout << express << " = "; caluValue(postexp); //計算字尾表示式的值 cout << "\n\n"; free(op); free(postexp); } }
stack.h
#include<stdlib.h>
#include<iostream>
using namespace std;
typedef char Elemtype;
typedef struct LinkStack
{
Elemtype data;
struct LinkStack *next;
}stackL;
//初始化
void InitStackL(stackL *lst)
{
lst->next = NULL;
}
//判斷是否為空,為空則返回1
int StackLEmpty(stackL *lst)
{
return (lst->next == NULL);
}
//壓入
void PushL(stackL *lst, Elemtype x)
{
stackL *p;
p = (stackL*)malloc(sizeof(stackL));
p->next = lst->next;
p->data = x;
lst->next = p;
}
//彈出
Elemtype PopL(stackL* lst)
{
stackL *toFree;
if (lst->next == NULL);
//cout << "the stack is empty\n";
else
{
Elemtype x;
x = (lst->next)->data;
toFree = lst->next;
lst->next = (lst->next)->next;
free(toFree);
return x;
}
return 0;
}
//獲取棧頂元素
Elemtype GetTopL(stackL* lst)
{
if (lst->next == NULL);
//cout << "the stack is empty\n";
else
{
Elemtype x;
x = lst->next->data;
return x;
}
return 0;
}