带括号的表达式求值
问题和上一篇博客一样,只是在表达式中加入了括号。
思路和上一篇博客的差异不大,只是在处理左右括号的优先级时需要注意一下:
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;
}
运行结果:
种一棵树最好的时间是十年前,其次是现在。