【C语言】 利用顺序表实现使用运算符优先数法对表达式求值
题目要求
本题要求编写程序,对任一输入的一个算术表达式,用运算符优先数法计算并输出其值。
【假设条件】
本题假定:
(1) 表达式只包含双目运算符,即: +,-,*,/
(2) 假定表达式一定是合法的,且其中的数字均为1位整数
题目分析
首先我们需要认识到什么时运算符优先法。
在常规的计算中,我们通常会用到’+’、’-’、’*’、’/'四种基本双目运算符来进行,而在这四种符号中,我们知道,如果是一个表达式中出现了这四个符号,那么遵循“先乘除,后加减”的运算规则,同时,“+”和“-”处在同一级,应遵循从左到右依次计算,同理“×”和“÷”。那么,根据此规则,我们可以用数值对不同优先级进行定义。
我们规定,“+”和“-”的等级数值为1,“×”和“÷”的等级值高于前两者为2(当然,你可以自行定义数值,只要满足加减的等级低于乘除的等级,且加和减的等级相等即可)。并且,为了方便操作,我们将符号栈的栈底默认放置一个“#”,并将它赋值为0(最低值),这样,在进行push和pop操作时,我们可以通过“#”来判断符号栈是否是空了。(或者你也可以放置一个“=”,赋值0)。
思考一下,怎么判断什么时候该push符号,什么时候pop符号呢?
- 入栈 判断待插入的符号与原符号栈顶等级大小,如果待插入的符号等级大于栈顶符号等级时,才插入该符号,并将栈顶向上移动一位。(比如:先乘除、若同级的话,应该遵循从左至右,先插入的符号在左边)
- 出栈 当待插入的符号等级小于栈顶符号等级时,将栈顶符号取出来,并且取出来两位数值,进行运算。在运算的过程中,要注意更新符号位栈顶的运算级,并与待插入的运算符等级进行判断。只要待插入的符号等级大于栈顶可,就终止出栈的操作,回到入栈。
代码实现如下
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define maxsize 1024
typedef struct node{
int top1;
int num[maxsize];
}Lnum;//定义为装数字的栈1
typedef struct node1{
int top2;
char fu[maxsize];
}Lchar;//定义装符号的栈2
int creat(char fix[]){//创建运算式
char ch;
int i=0;
while((ch=getchar())!='\n'){
fix[i]=ch;
i++;
}
return i;
}
int panduan(char ch1){//赋值判断四种基本运算符号和默认符号的优先级
switch(ch1){
case '*':return 2;break;
case '/':return 2;break;
case '+':return 1;break;
case '-':return 1;break;
case '#':return 0;break;
default:return -1;break;//错误符号,返回-1
}
}
int cal(char fix[],int num){
Lnum *stack1;
stack1=(Lnum*)malloc(sizeof(Lnum));//创建数字栈
Lchar *stack2;
stack2=(Lchar*)malloc(sizeof(Lchar));//符号栈
int flag1,flag2,i,temp,temp1;//先声明变量
stack1->top1=0;//初始化栈顶
stack2->top2=0;
stack2->fu[stack2->top2]='#';//符号栈的底部是'#'
for(i=0;i<num;++i){//遍历运算式,将不同类型的符号入栈
if((fix[i]-'0')>=1&&(fix[i]-'0')<=9){
stack1->num[stack1->top1]=fix[i]-'0';//注意运算式是字符形式,需要减'0'来得到int类型的数值
stack1->top1++;//每一次数字入栈后,栈顶就指向上面一层,故下面进行运算时需要先把栈顶指针往下回一个
}else{
flag1=panduan(stack2->fu[stack2->top2]);//判断符号栈顶指针所指向的运算符优先等级
flag2=panduan(fix[i]);//判断此时待装入的符号优先等级
if(flag2>flag1){//只有待装入符号优先级大于原栈顶优先级,才装入
stack2->top2++;
stack2->fu[stack2->top2]=fix[i];
}else{//否则,数值栈取两位数,符号位取一位符号进行运算
stack1->top1--;
while(flag2<=flag1){
switch(stack2->fu[stack2->top2]){
case '+':temp=(stack1->num[(stack1->top1)-1]+stack1->num[(stack1->top1)]);break;
case '-':temp=(stack1->num[(stack1->top1)-1]-stack1->num[(stack1->top1)]);break;
case '*':temp=(stack1->num[(stack1->top1)-1]*stack1->num[(stack1->top1)]);break;
case '/':temp=(stack1->num[(stack1->top1)-1]/stack1->num[(stack1->top1)]);break;
}
stack1->top1--;
stack1->num[stack1->top1]=temp;
stack2->top2--;
flag1=panduan(stack2->fu[stack2->top2]);
}
stack2->top2++;
stack1->top1++;
stack2->fu[stack2->top2]=fix[i];
}
}
}
stack1->top1--;//入栈操作结束后数值指针始终在上面一层,所以需要将指针取回来
while(stack2->top2!=0){//入栈结束,将栈内保存的符号和数值取出来进行运算
switch(stack2->fu[stack2->top2]){
case '+':temp1=(stack1->num[(stack1->top1)-1]+stack1->num[(stack1->top1)]);break;
case '-':temp1=(stack1->num[(stack1->top1)-1]-stack1->num[(stack1->top1)]);break;
case '*':temp1=(stack1->num[(stack1->top1)-1]*stack1->num[(stack1->top1)]);break;
case '/':temp1=(stack1->num[(stack1->top1)-1]/stack1->num[(stack1->top1)]);break;
}
stack1->top1--;//取了两个数,但是还需要将运算结果装回,所以只需要栈顶指针往栈底下移一位即可
stack1->num[stack1->top1]=temp1;
stack2->top2--; //符号栈栈顶指针下移一位
}
int r = stack1->num[stack1->top1];//返回运算结果
free(stack1);//释放两栈
free(stack2);
return r;
}
int main(){
char fix[maxsize];
int num=creat(fix);//创建一个装运算式子的字符串
int result=cal(fix,num);//计算结果,传回
printf("最终的计算结果为:%d\n",result);
}
PS:CS专业小透明,如果发现错误,还请各位大佬们不吝赐教。