表达式求值
Posted Amysear
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了表达式求值相关的知识,希望对你有一定的参考价值。
表达式求值问题
①问题描述
表达式是数据运算的基本形式。人们的书写习惯是中缀式,如: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以上是关于表达式求值的主要内容,如果未能解决你的问题,请参考以下文章