C语言 数据结构实训3(逆波兰计算器问题)

四则运算表达式求值

表达式求值是程序设计语言编译中的一个最基本的问题。它的实现是栈应用的一个典型例子。要对表达式正确求值,首先要能够正确解释表达式。例如,要对算数表达式

7+(4-2)*3+12/2

求值,首先要了解算数四则运算的规则。可归纳为:

(1)先乘除后加减;

(2)从左到右算;

(3)先括号内,后扩号外

为了实现四则运算,对我们人类来说通常采用的是中缀表达式,及我们平时见到的四则运算表达式,例如:

3+4*3-6;3/2+6*(4-2);9-8/6+1;

对于人类的思维结构来说,这种写法是便于计算的,而对计算机来说,这种写法的表达式却是非常复杂的,相对的,逆波兰式(即后缀表达式)却是相对简单的写法,例如:

3+4*3-6的逆波兰式为3 4 3 * + 6 -

3/2+6*(4-2)的逆波兰式为3 2 / 6 4 2 - * +

9-8/6+1的逆波兰式为9 8 6 / - 1 +

可以概括为根据算数的规则,先把要进行运算的数放在前面,而运算的符号放在两个数的后面,可以发现,在对每个符号进行运算时,每个符号的前面至少都有两个数,这两个数便是要进行运算的数。

回到逆波兰计算器问题,当我们输入一个四则运算式,根据这种方法,我们可以分配两个栈,一个用来存放数字或是计算的结果,另一个栈来存放运算符号。

(1)当遇到数字时,把数字压入数字栈,遇到符号时,判断当前符号与符号栈的栈顶符号的优先级;

(2)若当前符号的优先级大于栈顶符号的优先级,则将符号压入符号栈;

(3)若当前符号的优先级小于或等于栈顶符号的优先级,那么就从数字栈取出两个符号进行运算,将运算结果压入数字栈;

(4)再比较当前符号和栈顶符号优先级的大小,直到符号栈为空或栈顶符号的优先级大于当前符号。

(5)若遇到‘(’直接入栈,遇到‘)’则对括号内的表达式进行运算

代码如下:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <stdbool.h>
  4 #include <string.h>
  5 #define MAXSIZE 100
  6 typedef struct{//顺序栈存储结构
  7     char data[MAXSIZE];
  8     int top; 
  9 }Sqstack;
 10 void InitStack(Sqstack *s){//初始化栈
 11     s->top=-1;
 12 }
 13 bool InsertStack(Sqstack *s,char c){//入栈
 14     if(s->top>=MAXSIZE-1) return false;
 15     s->top++;
 16     s->data[s->top]=c;
 17     return true;
 18 }
 19 bool DeleteStack(Sqstack *s,char *c){//出栈
 20     if(s->top==-1)return false;
 21     *c=s->data[s->top];
 22     s->top--;
 23     return true;
 24 }
 25 bool Gettop(Sqstack *s,char *c){//取栈顶元素
 26     if(s->top==-1)return false;
 27     *c=s->data[s->top];
 28     return true;
 29 }
 30 int Arrayprior(char c){//判断符号的优先级
 31     switch(c){
 32         case '(': return 0;
 33         case '+':
 34         case '-': return 1;
 35         case '*':
 36         case '/': return 2;//最高优先级* /
 37         default : return -1;
 38     }
 39 }
 40 void ExeData(Sqstack *data,char ope){/*数字栈元素进行运算*/
 41     char n,m,t;
 42         //依次获得数值栈的栈顶两个数
 43     DeleteStack(data,&m);
 44     DeleteStack(data,&n);
 45         //运算
 46     switch(ope){
 47         case '+': t=m+n;break;
 48         case '-': t=n-m;break;
 49         case '*': t=m*n;break;
 50         case '/': t=n/m;break;
 51     }
 52         //计算结果再次入栈
 53     InsertStack(data,t);
 54 }
 55 void NiBolan(Sqstack *sope,Sqstack *data,char ope){
 56     char oldope;
 57         //如果sope符号栈是空栈或者符号为‘(’
 58     if(sope->top==-1 || ope=='('){
 59         InsertStack(sope,ope);
 60         return;
 61     }
 62         //获取符号栈栈顶元素
 63     Gettop(sope,&oldope);
 64         //将当前的符号栈的栈顶符号与传入的符号进行优先级比较
 65     if(Arrayprior(oldope)<Arrayprior(ope)){
 66         InsertStack(sope,ope);
 67         return;
 68     }
 69     while(Arrayprior(oldope)>=Arrayprior(ope)){
 70         DeleteStack(sope,&oldope);
 71         printf("%c ",oldope);
 72         //将当前栈顶的符号取出与数字栈中顶端的两个数字进行计算
 73         ExeData(data,oldope);
 74         //符号栈为空则终止break
 75         if(sope->top==-1)break;
 76         //否则再次取出一个符号进行比较
 77         Gettop(sope,&oldope);
 78     }    
 79         //将传入的符号入栈
 80     InsertStack(sope,ope);
 81 }
 82 void ViceNiBolan(Sqstack *sope,Sqstack *data){
 83     char oldope;
 84     Gettop(sope,&oldope);
 85     while(oldope!='('){
 86     //当前符号出栈然后将数字出栈两个进行计算,在括号内优先级最高
 87         DeleteStack(sope,&oldope);
 88         printf("%c ",oldope);
 89         ExeData(data,oldope); 
 90         if(sope->top==-1)break;
 91     //直到出现‘(’
 92         Gettop(sope,&oldope);
 93     }
 94     //最后还要将左括号丢弃
 95     DeleteStack(sope,&oldope);
 96 } 
 97 int main(){
 98     Sqstack *sope,*data;
 99     data=(Sqstack *)malloc(sizeof(Sqstack));
100     InitStack(data);
101     sope=(Sqstack *)malloc(sizeof(Sqstack));    
102     InitStack(sope);
103     char str[100];
104     printf("输入中缀表达式:");
105     gets(str);
106     char oldope;
107     int i=0;
108     int value=0;
109     int flag=0;
110     printf("输出后缀表达式为:");
111     while(str[i]!='\0'){
112         if(str[i]>='0' && str[i]<='9'){
113             value=value*10+str[i]-'0';
114             flag=1;
115         }else{
116             if(flag==1){
117                 InsertStack(data,value);
118                 printf("%d ",value);
119                 flag=0;
120                 value=0;
121             }
122             if(str[i]!=')'){
123                 NiBolan(sope,data,str[i]);
124             }else{
125                 ViceNiBolan(sope,data);
126             }
127         }
128         i++;    
129     }
130 //如果value里面还有数值,将其入栈 
131     if(value){
132         printf("%d ",value);
133         InsertStack(data,value);
134     }
135     while(sope->top!=-1){
136         DeleteStack(sope,&oldope);
137         printf("%c ",oldope);
138         ExeData(data,oldope);
139     }
140     printf("\n中缀表达式的值为:%d\n",data->data[0]);
141     return 0;     
142 }
143                     

代码运行效果:

 

代码如有问题,欢迎指正交流!!

posted @ 2021-10-20 17:49  旺旺哈  阅读(328)  评论(0)    收藏  举报