本文是对严蔚敏老师的数据结构一书中,第3.2.5一节 表达式求值问题的实现

采用的基本思想是“算符优先法”,即:

  (1)先乘除,后加减;

  (2)从左到右计算;

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

实现的方式:采用两个工作栈,一个寄存运算符;一个寄存运算数;

  (1)首先置操作数栈为空,置操作符栈'='作为栈底元素;

  (2)依次分析表达式的每个字符,如果是操作数则进操作数栈,若是操作符,则和操作符栈的栈顶元素比较优先级后作出相应操作,直到整个表达式求值完毕(即字符串分析完毕或操作符栈的栈顶元素为'=')

 

运算符优先级采用二维数据保存,优先关系如下图:

源码如下:

CalcExp.c

  1 /*********************************************************************
  2 *:
  3 *:          Author: dspeeding
  4 *:          Copyright (c) 2012, dspeeding
  5 *:
  6 *:        Created at: 2013.08.07
  7 *:     Last modified: 2013.08.07  
  8 *:             
  9 *:      Introduction: 表达式求值(栈实现)
 10 *:                    
 11 *:
 12 *:*********************************************************************/
 13 #include <stdio.h>
 14 #include <string.h>
 15 #include "LinkListStack.h"
 16 
 17 
 18 LinkListStack gStack_opt;            /*操作符*/
 19 LinkListStack gStack_opnum;            /*操作数*/
 20 
 21 void Trim(char* str) 
 22 {
 23     char szTmp[1025];
 24     memset(szTmp,0,sizeof(szTmp));
 25     char *p = NULL;
 26     char *q = NULL;
 27     int i,nLen;
 28     
 29     p = str;
 30     q = szTmp;
 31     
 32     nLen = strlen(str);
 33     for(i = 0;i < nLen;i++)
 34     {
 35         if(str[i] != ' ')
 36         {
 37             *q++ = str[i];
 38         }
 39     }
 40     
 41     //如果输入没有=号则程序自动加入该等号
 42     if(*(q-1)!='=')
 43     {
 44         *q++='=';
 45     }
 46     *q='\0';
 47     
 48     strcpy(str,szTmp);
 49 }
 50 
 51 
 52 
 53 char *getLine(){
 54     static char str[1025];
 55     fgets(str, 1024, stdin);
 56     int len = strlen(str);
 57     while(--len >= 0){
 58             if(str[len]=='\r' || str[len]=='\n')
 59                     str[len] = '\0';
 60             else
 61                     break;
 62     }
 63     return str;
 64 }
 65 
 66 
 67 /*检查表达式中有无违法字符 */
 68 int CheckString(const char* str)
 69 {
 70     int i,nLen;
 71     nLen = strlen(str);
 72     
 73     for(i = 0;i < nLen;i++)
 74     {
 75         if(str[i]<'0'&&str[i]>'9'&&str[i]!='('&&str[i]!=')'
 76                 &&str[i]!='*'&&str[i]!='+'&&str[i]!='-'&&str[i]!='/'
 77                 &&str[i]!='=')
 78         {
 79             return 1;
 80         }
 81     }
 82     return 0;
 83 }
 84 
 85 //比较2个操作符的优先级
 86 char precede(char x,char y)
 87 {
 88     int i,j;
 89     int form[7][7]={
 90             { 1, 1,-1,-1,-1, 1, 1},
 91             { 1, 1,-1,-1,-1, 1, 1},
 92             { 1, 1, 1, 1,-1, 1, 1},
 93             { 1, 1, 1, 1,-1, 1, 1},
 94             {-1,-1,-1,-1,-1, 0, 2},
 95             { 1, 1, 1, 1, 2, 1, 1},
 96             {-1,-1,-1,-1,-1, 2, 0}};
 97     switch(x)
 98     {
 99         case '+':i=0;break;
100         case '-':i=1;break;
101         case '*':i=2;break;
102         case '/':i=3;break;
103         case '(':i=4;break;
104         case ')':i=5;break;
105         case '=':i=6;break; 
106     }
107     switch(y){
108         case '+':j=0;break;
109         case '-':j=1;break;
110         case '*':j=2;break;
111         case '/':j=3;break;
112         case '(':j=4;break;
113         case ')':j=5;break;
114         case '=':j=6;break; 
115     }
116     
117     if(form[i][j] == 1)
118     {
119         return '>';
120     }
121     else if(form[i][j] == -1)
122     {
123         return '<';
124     }
125     else
126     {
127         return '=';
128     }
129 }
130 
131 
132 int calc(int num1,int num2,char opt)
133 {
134     switch(opt)
135     {
136         case '+':
137             return num1 + num2;
138         case '-':
139             return num1 - num2;
140         case '*':
141             return num1 * num2;
142         case '/':
143             if(num2 == 0)
144             {
145                 return 0;
146             }
147             return num1 / num2;
148     }
149 }
150 
151 int AnalyString(char* str)
152 {
153     char opt = '=';
154     char szTmp[1024];
155     int num1,num2,num_tmp;
156     char *p = NULL;
157     char *q = NULL;
158     char byRet;
159     ElemType outData;
160     int num_result;
161     
162     
163     memset(szTmp,0,sizeof(szTmp));
164     //首先把'='入栈
165     PushLinkListStack(&gStack_opt, (PElemType)&opt);
166     p = str;
167     q = szTmp;
168     GetTopLinkListStack(&gStack_opt, &outData);
169     while(*p!='\0' || outData != '=')
170     {
171         if(*p>='0' && *p<='9')
172         {
173             //操作数
174             *q++ = *p++;
175         }
176         else
177         {
178             //操作符
179             if(strlen(szTmp)!=0)
180             {
181                 num_tmp = atoi(szTmp);
182                 memset(szTmp,0,sizeof(szTmp));
183                 q = szTmp;
184                 
185                 //操作数入栈
186                 printf("操作数[%d]入栈\n",num_tmp);
187                 PushLinkListStack(&gStack_opnum, (PElemType)&num_tmp);
188             }
189             opt = *p;
190             GetTopLinkListStack(&gStack_opt, &outData);
191             byRet = precede((char)outData, opt);
192             switch(byRet)
193             {
194                 case '<':
195                     printf("操作符[%c]入栈\n",opt);
196                     PushLinkListStack(&gStack_opt, (PElemType)&opt);
197                     p++;            //字符串指针后移
198                     break;
199                 case '>':
200                     //在>时 进行运算完毕后p不进行++操作
201                     PopLinkListStack(&gStack_opnum, &num2);
202                     printf("操作数[%d]出栈\n",num2);
203                     PopLinkListStack(&gStack_opnum, &num1);
204                     printf("操作数[%d]出栈\n",num1);
205                     PopLinkListStack(&gStack_opt, &outData);
206                     printf("操作符[%c]出栈\n",(char)outData);
207                     num_result = calc(num1, num2, (char)outData);
208                     PushLinkListStack(&gStack_opnum, (PElemType)&num_result);
209                     printf("操作数[%d]入栈\n",num_result);
210                     break;
211                 case '=':
212                     PopLinkListStack(&gStack_opt, &outData);
213                     printf("操作符[%c]出栈\n",(char)outData);
214                     p++;            //字符串指针后移
215                     break;
216             }
217         }
218     GetTopLinkListStack(&gStack_opt, &outData);
219     }
220     return 0;
221 }
222 
223 int main()
224 {
225     int outData;
226     InitLinkListStack(&gStack_opt);
227     InitLinkListStack(&gStack_opnum);
228     
229     char *input = getLine();
230     Trim(input);
231     if(CheckString(input))
232     {
233         printf("输入表达式错误\n");
234         return 1;
235     }
236     printf("输入数据[%s]\n", input);
237     
238     if(AnalyString(input))
239     {
240         printf("解析表达式错误\n");
241         return 1;
242     }
243     if(IsEmptyLinkListStack(&gStack_opt) != 0)
244     {
245         printf("表达式错误\n");
246         return -1;
247     }
248     printf("表达式结果:\t");
249     if(IsEmptyLinkListStack(&gStack_opnum))
250     {
251         if(PopLinkListStack(&gStack_opnum, &outData))
252         {
253             printf("pop stack fail\n");
254         }
255         visit(&outData);
256     }    
257     return 0;
258 }

 

代码中用到的栈为(4)数据结构——栈(链表)实现 一节中的链表栈,且ElemType的实现同此节。

结果如下:

由于ElemType的限制,用的栈只支持整数运算,如果支持小数运算则需要两个栈的栈元素定义不同才能实现。

目前对除零的操作结果为0,不支持如+4-(-3)之类带正负数的操作

posted on 2013-08-07 15:01  dspeeding  阅读(1415)  评论(0编辑  收藏  举报