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
代码运行效果:

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

浙公网安备 33010602011771号