表达式求值

 

表达式求值问题

①问题描述

表达式是数据运算的基本形式。人们的书写习惯是中缀式,如:11+22*(7-4)/3。中缀式的计算按运算符的优先级及括号优先的原则,相同级别从左到右进行计算。表达式还有后缀式(如:22 7 4 - * 3 / 11 +)和前缀式(如:+ 11 / * 22 – 7 4 3)。后缀表达式和前缀表达式中没有括号,给计算带来方便。如后缀式计算时按运算符出现的先后进行计算。本设计的主要任务是进行表达式形式的转换及不同形式的表达式计算。

②基本要求

l  从文件或键盘读入中缀表达式。

l  设计操作数为多位整数,操作符为加、减、乘、除、求模的中缀表达式求值算法。

l  设计将中缀表达式转换为后缀表达式的算法。

l  设计将中缀表达式转换为前缀表达式的算法。

l  设计后缀表达式求值算法。

l  设计前缀表达式求值算法。

l  输出各种形式的表达式。

③设计要点提示

l  算数表达式的计算往往是通过栈来实现的。

l  读入或扫描表达式的同时,完成运算符和操作数的识别处理。

l  识别操作数时,注意将其字符序列转换成整数(如:‘15’→15)或实数(如:‘15.4’ →15.4)形式进行存储。

l  可以将表达式转换成一棵二叉树,通过先序、中序、后序遍历得到前缀、中缀、后缀表达式。

l  仿表1来构建测试用例。

表1 表达式计算测试用例示例

测试项目

测试用例

预期结果

基本测试

3

3

1+2*3-4/2

5

11+22

33

1+22*(5-3)/4

12

(((2)))-3

-1

 

容错测试

1+2(

表达式出错提示

2/0

表达式出错提示

2%0

表达式出错提示

(2-4)Ù3.1

表达式出错提示

2+3)(-5

表达式出错提示

(((2))-3

表达式出错提示

2.5%2

表达式出错提示

1+++1

表达式出错提示

2 2

表达式出错提示

1#1

表达式出错提示

表达式出错提示

  1 #include <iostream>
  2 #include<string.h>
  3 #include<ctype.h>
  4 #include<malloc.h> /* malloc()等 */
  5 #include<limits.h> /* INT_MAX等 */
  6 #include<stdio.h> /* EOF(=^Z或F6),NULL */
  7 #include<stdlib.h> /* atoi() */
  8 #include<io.h> /* eof() */
  9 #include<math.h> /* floor(),ceil(),abs() */
 10 #include<process.h> /* exit() */
 11 /* 函数结果状态代码 */
 12 #define TRUE 1
 13 #define FALSE 0
 14 #define OK 1
 15 #define ERROR 0
 16 #define INFEASIBLE -1
 17 #define OVERFLOW 3
 18 /* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
 19 typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
 20 typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
 21 using namespace std;
 22 typedef char SElemType;
 23 #define STACK_INIT_SIZE 100 //存储空间初始分配量
 24 #define STACKINCREMENT 10//存储空间分配增量
 25 
 26 
 27 /*——————————————————————————栈的操作——————————————————————————*/
 28 typedef struct{
 29    SElemType * base;//在栈构造之前和销毁之后,base的值为NULL
 30    SElemType * top;//栈顶指针
 31    int stacksize;
 32 }SqStack;
 33 Status InitStack(SqStack &S)
 34 {//构造一个空栈
 35     S.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
 36     if(!S.base) exit(OVERFLOW);
 37     S.top=S.base;
 38     S.stacksize=STACK_INIT_SIZE;
 39     return OK;
 40 }
 41 Status DestroyStack(SqStack &S)
 42 {//销毁栈
 43     free(S.base);
 44     S.top=NULL;
 45     S.base=NULL;
 46     S.stacksize=0;
 47     return OK;
 48 }
 49 
 50 Status StackEmpty(SqStack S)
 51 {
 52     if(S.top==S.base) return TRUE;
 53     else return FALSE;
 54 }
 55 int StackLength(SqStack S)
 56 {
 57     return S.top-S.base;
 58 }
 59 Status GetTop(SqStack S,SElemType &e)
 60 {
 61     if(S.top>S.base)
 62         {e=*(S.top-1);return OK;}
 63     else return ERROR;
 64 }
 65 Status Push(SqStack &S,SElemType e)
 66 {
 67     if(S.top-S.base==S.stacksize)//若栈满,追加存储空间
 68     {
 69         S.base=(SElemType *) realloc (S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));
 70         if(!S.base) exit(OVERFLOW);//存储内存分配失败
 71         S.top=S.base+S.stacksize;
 72         S.stacksize += STACKINCREMENT;
 73     }
 74     *(S.top)=e;//可直接使用 *S.top++=e;
 75     S.top++;
 76     return OK;
 77 }
 78 
 79 Status Pop(SqStack &S,SElemType &e)
 80 {
 81     if(S.top==S.base)
 82     {
 83         cout<<"表达式错误,溢出!!"<<endl;
 84         exit(OVERFLOW);
 85     }
 86     e=*--S.top;
 87     return OK;
 88 }
 89 Status StackTraverse(SqStack S, void(* visit)(SElemType))
 90 {
 91     while(S.top>S.base)
 92         visit(*S.base++);
 93     printf("\n");
 94     return OK;
 95 }
 96 
 97 
 98 //表达式求值
 99 char Precede(SElemType c1,SElemType c2)//判断c1,c2的优先关系,栈顶元素是c1,如果要入栈的元素c2优先权小(>),
100                                        //则弹出c1进行运算,再把c2继续尝试入栈,c1栈底,c2入栈运算符
101 {
102     char f;
103     switch(c2)
104     {
105         case '.' : f='<';
106                    break;
107         case '+' :
108         case '-' : if(c1=='('||c1=='\n') f='<';
109                    else f='>';
110                    break;
111 
112         case '*' :
113         case '/' : if(c1=='*'||c1=='/'||c1==')') f='>';
114                    else f='<';
115                    break;
116         case '(' : if(c1==')')
117                     {
118                         printf("括号输入不合法!");
119                         exit(ERROR);
120                     }
121                    else f='<';
122                    break;
123         case ')' : switch(c1)
124                     {
125                     case '\n':
126                               printf("缺乏左括号!");
127                               exit(ERROR);
128                     case '(': f='=';
129                               break;
130                     default : f='>';
131                     }
132                     break;
133         case '\n' : switch(c1)
134                    {
135                      case '\n': f='=';
136                                 break;
137                     case '(':
138                         printf("缺少右括号!");
139                         exit(ERROR);
140                     default : f='>';
141                    }
142     }
143     return f;
144 }
145 Status In(SElemType c)
146 { // 判断c是否为7种运算符之一
147     switch(c)
148     {
149         case '.' :
150         case '+' :
151         case '-' :
152         case '*' :
153         case '/' :
154         case '(' :
155         case ')' :
156         case '\n' :return TRUE;
157         default  :return FALSE;
158     }
159 }
160 SElemType Operate(SElemType a,SElemType theta,SElemType b)
161 { // 做四则运算a theta b,返回运算结果
162     switch(theta)
163     {
164         case '+':return a+b;
165         case '-':return a-b;
166         case '*':return a*b;
167         case '.':return a;
168     }
169     if(b!=0)  return a/b;
170     else
171     {
172         cout<<"分母不能为0!"<<endl;
173         exit(OVERFLOW);
174     }
175 }
176 SElemType EvaluateExpression(SElemType M[100])
177 {//算术表达式求值的算符优先算法。设OPTR和OPND分别为运算符栈和运算数栈。
178  //OP为运算符集合
179     SqStack OPTR,OPND;
180     SElemType a,b,c,x;
181     int m=0,n=0;
182     InitStack(OPTR); Push(OPTR,'\n');
183     InitStack(OPND);
184 
185     GetTop(OPTR,x);
186 
187     int i=1;
188 
189     while(M[i]!='\n' || x!='\n')//当运算符栈栈顶元素为‘\n’,并且此时'\n'尝试入栈时,作为表达式结束的标志
190     {
191 
192         if(M[i]>='0'&&M[i]<='9') // M[i]是操作数
193         {
194             while(M[i]>='0'&&M[i]<='9')
195             {m=m*10+(M[i]-'0');i++;}
196             Push(OPND,m); // 将该操作数的值(不是ASCII码)压入运算数栈OPND
197             m=0;
198 
199         }
200         else if(In(M[i]))   // M[i]是运算符
201          switch(Precede(x,M[i]))
202         {
203           case '<': //栈顶优先权低,进栈
204             Push(OPTR,M[i]);i++;
205             break;
206           case '=': //脱括号并接受下一字符
207             Pop(OPTR,x);i++;
208             break;
209           case '>': //退栈并将运算结果入栈,不再getchar,将当前字符继续尝试压栈
210             Pop(OPTR,x);
211             Pop(OPND,a);
212             Pop(OPND,b);
213             Push(OPND,Operate(b,x,a));
214             break;
215         }
216 
217       else // c是非法字符
218       {
219         printf("出现非法字符\n");
220         exit(ERROR);
221       }
222 
223       GetTop(OPTR,x); // 将运算符栈OPTR的栈顶元素赋给x
224     }
225     Pop(OPND,x);
226 
227     if(!StackEmpty(OPND)) // 运算数栈OPND不空(运算符栈OPTR仅剩′\n′ )
228         {
229             printf("表达式不正确\n");
230             exit(ERROR);
231         }
232 
233     return x;
234 }
235 
236 Status InToPost(SElemType M[100])
237 {
238     SqStack OPTR,OPND;
239     SElemType a,b,c,x;
240     int m=0,n=0;
241     InitStack(OPTR); Push(OPTR,'\n');
242     InitStack(OPND);
243     GetTop(OPTR,x);
244     int i=1;
245     while(M[i]!='\n' || x!='\n')//当运算符栈栈顶元素为‘\n’,并且此时'\n'尝试入栈时,作为表达式结束的标志
246     {
247 
248         if(M[i]>='0'&&M[i]<='9') // M[i]是操作数
249         {
250             while(M[i]>='0'&&M[i]<='9')
251             {m=m*10+(M[i]-'0');i++;}
252             Push(OPND,m); // 将该操作数的值(不是ASCII码)压入运算数栈OPND
253             cout<<m;
254             m=0;
255 
256         }
257         else if(In(M[i]))   // M[i]是运算符
258          switch(Precede(x,M[i]))
259         {
260           case '<': //栈顶优先权低,进栈
261             Push(OPTR,M[i]);i++;
262             break;
263           case '=': //脱括号并接受下一字符
264             Pop(OPTR,x);i++;
265             break;
266           case '>': //退栈并将运算结果入栈,不再getchar,将当前字符继续尝试压栈
267             Pop(OPTR,x);cout<<x;
268             Pop(OPND,a);
269             Pop(OPND,b);
270             Push(OPND,Operate(b,x,a));
271             break;
272         }
273 
274       else // c是非法字符
275       {
276         printf("出现非法字符\n");
277         exit(ERROR);
278       }
279 
280       GetTop(OPTR,x); // 将运算符栈OPTR的栈顶元素赋给x
281     }
282     Pop(OPND,x);
283 
284     if(!StackEmpty(OPND)) // 运算数栈OPND不空(运算符栈OPTR仅剩′\n′ )
285         {
286             printf("表达式不正确\n");
287             exit(ERROR);
288         }
289 
290     return OK;
291 }
292 int ArrayLength(SElemType M[100])
293 {//求数组的长度,不包含'\n'
294     int j=1;
295     while(M[j]!='\n')
296     {
297         j++;
298     }
299     return j-1;
300 }
301 
302 Status InToPre(SElemType M[100])
303 {//中缀表达式转前缀
304     SqStack OPTR,RESULT;
305     SElemType a,b,c,x;
306     int m=0,n=0;
307     InitStack(OPTR); Push(OPTR,'\n');
308     InitStack(RESULT);
309     GetTop(OPTR,x);
310     int i=ArrayLength(M);
311     while(M[i]!='\n')//当运算符栈栈顶元素为‘\n’作为表达式结束的标志
312     {
313 
314         if(M[i]>='0'&&M[i]<='9') // M[i]是操作数,直接压入RESULT栈
315         {
316             int j=0;
317             while(M[i]>='0'&&M[i]<='9')
318             {m+=pow(10,j)*M[i];i--;}
319 
320             Push(RESULT,m); // 将该操作数的值(不是ASCII码)压入结果栈RESULT
321             m=0;
322 
323         }
324         else if(M[i]==')')//假如是右括号,直接将它压栈。
325         {
326             Push(OPTR,M[i]);
327             i--;
328         }
329         else if(M[i]=='(')//假如是左括号,栈中运算符逐个出栈并压入RESULT栈,直到遇到右括号。右括号出栈并丢弃。
330         {
331                 while(x!=')')
332                 {
333                     Pop(OPTR,x);Push(RESULT,x);
334                     GetTop(OPTR,x);
335                 }
336                 Pop(OPTR,x);//将OPTR中的')'弹出
337                 i--;
338         }
339         else if(In(M[i]))   // M[i]是其它运算符
340          switch(Precede(x,M[i]))
341         {
342           case '<': //栈顶优先权低,进栈
343             Push(OPTR,M[i]);i--;
344             break;
345           case '=': //脱括号并接受下一字符
346             Pop(OPTR,x);i--;
347             break;
348           case '>': //运算符较栈顶算符优先级低,弹出OPTR栈中算符,并存入RESULT栈,直至遇到优先级相等的算符或栈为空为止,然后将当前算符存入OPTR栈
349             if(x==')')
350             {
351                 Push(OPTR,M[i]);
352             }
353             else
354             {
355               while(Precede(x,M[i])=='>'&&StackLength(OPTR)>1)
356               {
357                   if(x==')') break;//如果遇到右括号退出循环
358                   else {Pop(OPTR,x);Push(RESULT,x); GetTop(OPTR,x);}
359               }
360               Push(OPTR,M[i]);
361 
362             }
363             i--;
364             break;
365          }
366 
367       else // c是非法字符
368       {
369         printf("出现非法字符\n");
370         exit(ERROR);
371       }
372       GetTop(OPTR,x); // 将运算符栈OPTR的栈顶元素赋给x
373     }
374 
375     while(StackLength(OPTR)>1) // 运算数栈OPND不空(运算符栈OPTR仅剩′\n′ )
376         {
377             Pop(OPTR,x);Push(RESULT,x);
378         }
379     while(StackLength(RESULT)>1)
380     {
381         Pop(RESULT,x);cout<<x;
382     }
383     GetTop(RESULT,x);cout<<x;
384     return OK;
385 }
386 
387 SElemType PostExpression(SElemType M[100])
388 {//算术表达式求值的算符优先算法。设OPTR和OPND分别为运算符栈和运算数栈。
389  //OP为运算符集合
390     SqStack OPND;
391     SElemType a,b,c,x;
392     int m=0,n=0;
393     InitStack(OPND);
394     int i=1;
395     while(M[i]!='\n')//当运算符栈栈顶元素为‘\n’,作为表达式结束的标志
396     {
397 
398         if(M[i]>='0'&&M[i]<='9') // M[i]是操作数
399         {
400             m=M[i]-'0';
401             Push(OPND,m); // 将该操作数的值(不是ASCII码)压入运算数栈OPND
402             i++;
403         }
404         else if(In(M[i]))   // M[i]是运算符
405          {
406             Pop(OPND,a);
407             Pop(OPND,b);
408             Push(OPND,Operate(b,M[i],a));
409             i++;
410          }
411 
412       else // c是非法字符
413       {
414         printf("出现非法字符\n");
415         exit(ERROR);
416       }
417     }
418     Pop(OPND,x);
419     return x;
420 }
421 
422 SElemType PreExpression(SElemType M[100])
423 {//算术表达式求值的算符优先算法。设OPTR和OPND分别为运算符栈和运算数栈。
424  //OP为运算符集合
425     SqStack OPND;
426     SElemType a,b,c,x;
427     int m=0,n=0;
428     InitStack(OPND);
429     int i=ArrayLength(M);
430     while(M[i]!='\n')//当运算符栈栈顶元素为‘\n’,作为表达式结束的标志
431     {
432 
433         if(M[i]>='0'&&M[i]<='9') // M[i]是操作数
434         {
435             m=M[i]-'0';
436             Push(OPND,m); // 将该操作数的值(不是ASCII码)压入运算数栈OPND
437             i--;
438         }
439         else if(In(M[i]))   // M[i]是运算符
440          {
441             Pop(OPND,a);
442             Pop(OPND,b);
443             Push(OPND,Operate(a,M[i],b));
444             i--;
445          }
446 
447       else // c是非法字符
448       {
449         printf("出现非法字符\n");
450         exit(ERROR);
451       }
452     }
453     Pop(OPND,x);
454     return x;
455 }
456 
457 int main()
458 {
459     system("color 70");
460     //表达式求值
461     printf("———————————表达式求值———————————");
462     cout<<endl;
463     char c;
464     printf("请输入算术表达式:\n");
465     SElemType M[100];
466     M[0]='\n';
467     c=getchar();
468     int j=1;
469     while(c!='\n')
470     {
471         M[j]=c;
472         c=getchar();
473         j++;
474     }
475     M[j]='\n';
476     int a=EvaluateExpression(M);//强制转换成int型
477     cout<<"运算结果为:"<<endl;
478     printf("%d\n",a); // 返回值(8位二进制,1个字节)按整型格式输出
479 
480 
481 
482     printf("———————————表达式转换———————————");
483     cout<<endl;
484     char c2;
485     printf("请输入算术表达式:\n");
486     SElemType M2[100];
487     M2[0]='\n';
488     c2=getchar();
489     int j1=1;
490     while(c2!='\n')
491     {
492         M2[j1]=c2;
493         c2=getchar();
494         j1++;
495     }
496     M2[j1]='\n';
497     printf("中缀表达式为:\n");
498     int i=1;
499     while(M2[i]!='\n')
500     {
501         if((M2[i]!='(')&&(M2[i]!=')')) {cout<<M2[i];i++;}
502         else i++;
503     }
504     cout<<endl;
505     printf("后缀表达式为:\n");
506     InToPost(M2);
507     cout<<endl;
508     cout<<"前缀表达式为:"<<endl;
509     InToPre(M2);
510     cout<<endl;
511 
512 
513     cout<<"——————————后缀表达式求值——————————"<<endl;
514     cout<<"请输入后缀表达式:"<<endl;
515     char c3;
516     SElemType M3[100];
517     M3[0]='\n';
518     c3=getchar();
519     int j3=1;
520     while(c3!='\n')
521     {
522         M3[j3]=c3;
523         c3=getchar();
524         j3++;
525     }
526     M3[j3]='\n';
527     int a3=PostExpression(M3);
528     cout<<"运算结果为:"<<endl;
529     printf("%d\n",a3);
530 
531     cout<<"——————————前缀表达式求值——————————"<<endl;
532     cout<<"请输入前缀表达式:"<<endl;
533     char c4;
534     SElemType M4[100];
535     M4[0]='\n';
536     c4=getchar();
537     int j4=1;
538     while(c4!='\n')
539     {
540         M4[j4]=c4;
541         c4=getchar();
542         j4++;
543     }
544     M4[j4]='\n';
545     int a4=PreExpression(M4);
546     cout<<"运算结果为:"<<endl;
547     printf("%d\n",a4);
548     return 0;
549 }

 

posted @ 2017-07-18 14:33  卉卉卉大爷  阅读(1080)  评论(0编辑  收藏  举报