問題和上一篇博客一樣,只是在表達式中加入了括號。
思路和上一篇博客的差異不大,只是在處理左右括號的優先級時需要注意一下:
1.左括號的優先級僅高於#;
2.但是遇見左括號時,不用和OPTR棧頂元素進行優先級比較,直接強制進OPTR棧;
3.遇到右括號,退OVS棧兩次,退OPTR棧一次,進行相應的運算操作,將計算結果壓入OVS棧,直到OPTR棧頂元素時左括號為止,並將左括號彈出OPTR棧;
代碼如下:
#include<stdio.h> #include<stdlib.h> #include<math.h> #include<stdbool.h> typedef struct node{ int data;//無論對於運算符還是運算數,都用int型變量來保存
node *next; }LinkStackNode, *LinkStack; void InitStack(LinkStack *S){//初始化鏈棧
*S = (LinkStack)malloc(sizeof(LinkStackNode)); (*S)->next = NULL; } int Push(LinkStack top, int x){// 進棧操作
LinkStackNode *temp; temp = (LinkStackNode*)malloc(sizeof(LinkStackNode)); if(temp == NULL) return 0; temp->data = x; temp->next = top->next; top->next = temp; return 1; } int Pop(LinkStack top, int *x){//出棧操作
LinkStackNode *temp; temp = top->next; if(temp == NULL) return 0; *x = temp->data; top->next = temp->next; free(temp); return 1; } int GetNum(char ch){//返回字符對應的數字
return ch - '0'; } bool IsEmpty(LinkStack top){//棧為空返回假
if(top->next == NULL) return false; return true; } int GetTop(LinkStack top){//返回棧頂元素
if(top->next == NULL) return 1; return top->next->data; } /*進行運算符優先級比較,用表列出所有可能出現的情況, ch1對應行,ch2對應列,每次找到對應的位置,直接返回 優先級比較結果*/
char Compare(char ch1, char ch2){ int i, j; char rela[7][7] = {{'=', '<', '<', '<', '<', '<', '<'}, {'>', '=', '=', '<', '<', '<', '>'}, {'>', '=', '=', '<', '<', '<', '>'}, {'>', '>', '>', '=', '=', '<', '>'}, {'>', '>', '>', '=', '=', '<', '>'}, {'>', '>', '>', '>', '>', '=', '>'}, {'>', '<', '<', '<', '<', '<', '='}, }; switch(ch1){ 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; } switch(ch2){ 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; } return rela[i][j]; } int Calculate(int a, char op, int b){//計算 a op b 的值
int c; switch(op){ case '-': c = a - b; break; case '+': c = a + b; break; case '*': c = a * b; break; case '/': c = a / b; break; case '^': c = pow(a, b); break; default : c = 0; } return c; } bool IsOperation(char ch){//判斷是不是操作符
if(ch == '#' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^' ) return true; return false; } int ExpEvaluation(){//實現
LinkStack ovs, optr; InitStack(&ovs); InitStack(&optr); Push(optr, (int)'#'); char ch = getchar(); int num = 0, a, b, t, op, zan; while(ch != '#' || (char)GetTop(optr) != '#'){ while(ch >= '0' && ch <= '9'){//如果數字不是一位數字,便把字符轉化為數字
num = num * 10 + GetNum(ch); ch = getchar(); } if(num != 0){//如果num不為0便進OVS棧
Push(ovs, num); num = 0;//把num置零
} else if(IsOperation(ch)){ switch(Compare(ch, (char)GetTop(optr))){//對運算符優先級進行比較,實現對應三種關系的操作
case '>': Push(optr, (int)ch); ch = getchar(); break; case '=': case '<': Pop(optr, &op); Pop(ovs, &a); Pop(ovs, &b); t = Calculate(b, (char)op, a); Push(ovs, t); break; } } else if(ch == '('){//遇見左括號直接進OPTR棧
Push(optr, (int)ch); ch = getchar(); } else if(ch == ')'){//遇見左括號
while((char)GetTop(optr) != '('){//直到棧頂元素為左括號結束本次循環
Pop(optr, &op); //OPTR退棧一次
Pop(ovs, &a);//OVS退棧兩次 ,進行相應的計算,把結果壓入OVS棧中
Pop(ovs, &b); t = Calculate(b, (char)op, a); Push(ovs, t); } Pop(optr, &op);//彈出左括號操作
ch = getchar(); } } t = GetTop(ovs);//取棧頂元素,返回最終計算結果
return t; } int main(){ printf("\n\nPlease input an expression(Ending with '#'):\n"); int ans = ExpEvaluation(); printf("%d\n", ans); return 0; }
運行結果: