表达式求值

http://www.cnblogs.com/flyingbread/archive/2007/02/03/638932.html

分析用堆栈解析算术表达式的基本方法。给出的示例代码能解析任何包括+,-,*,/,()和0到9数字组成的算术表达式。

中缀表达式就是通常所说的算术表达式,比如(1+2)*3-4。
后缀表达式是指通过解析后,运算符在运算数之后的表达式,比如上式解析成后缀表达式就是12+3*4-。这种表达式可以直接利用栈来求解。

中缀表达式翻译成后缀表达式的方法如下:

(1)从左向右依次取得数据ch。

(2)如果ch是操作数,直接输出。

(3)如果ch是运算符(含左右括号),则:
      a:如果ch = '(',放入堆栈。
      b:如果ch = ')',依次输出堆栈中的运算符,直到遇到'('为止。
      c:如果ch不是')'或者'(',那么就和堆栈顶点位置的运算符top做优先级比较。
          1:如果ch优先级比top高,那么将ch放入堆栈。
          2:如果ch优先级低于或者等于top,那么输出top,反复进行,直到ch优先级高于top或者栈为空,然后将ch放入堆栈。

(4)如果表达式已经读取完成,而堆栈中还有运算符时,依次由顶端输出。

如果我们有表达式(A-B)*C+D-E/F,要翻译成后缀表达式,并且把后缀表达式存储在一个名叫output的字符串中,可以用下面的步骤。

(1)读取'(',压入堆栈,output为空
(2)读取A,是运算数,直接输出到output字符串,output = A
(3)读取'-',此时栈里面只有一个'(',因此将'-'压入栈,output = A
(4)读取B,是运算数,直接输出到output字符串,output = AB
(5)读取')',这时候依次输出栈里面的运算符'-',然后就是'(',直接弹出,output = AB-
(6)读取'*',是运算符,由于此时栈为空,因此直接压入栈,output = AB-
(7)读取C,是运算数,直接输出到output字符串,output = AB-C
(8)读取'+',是运算符,它的优先级比'*'低,那么弹出'*',压入'+",output = AB-C*
(9)读取D,是运算数,直接输出到output字符串,output = AB-C*D
(10)读取'-',是运算符,和'+'的优先级一样,因此弹出'+',然后压入'-',output = AB-C*D+
(11)读取E,是运算数,直接输出到output字符串,output = AB-C*D+E
(12)读取'/',是运算符,比'-'的优先级高,因此压入栈,output = AB-C*D+E
(13)读取F,是运算数,直接输出到output字符串,output = AB-C*D+EF
(14)原始字符串已经读取完毕,将栈里面剩余的运算符依次弹出,output = AB-C*D+EF/-

计算算术表达式

当有了后缀表达式以后,运算表达式的值就非常容易了。可以按照下面的流程来计算。

(1)从左向右扫描表达式,一个取出一个数据data
(2)如果data是操作数,就压入堆栈
(3)如果data是操作符,就从堆栈中弹出此操作符需要用到的数据的个数,进行运算,然后把结果压入堆栈
(4)如果数据处理完毕,堆栈中最后剩余的数据就是最终结果。

比如我们要处理一个后缀表达式1234+*+65/-,那么具体的步骤如下。

(1)首先1,2,3,4都是操作数,将它们都压入堆栈
(2)取得'+',为运算符,弹出数据3,4,得到结果7,然后将7压入堆栈
(3)取得'*',为运算符,弹出数据7,2,得到数据14,然后将14压入堆栈
(4)取得'+',为运算符,弹出数据14,1,得到结果15,然后将15压入堆栈
(5)6,5都是数据,都压入堆栈
(6)取得'/',为运算符,弹出数据6,5,得到结果1.2,然后将1.2压入堆栈
(7)取得'-',为运算符,弹出数据15,1.2,得到数据13.8,这就是最后的运算结果

 

  1 class ComputeExpr
  2 {
  3 public:
  4     string transPosExpr(string s);        //将中缀表达式转化成后缀表达式,比如(1+2)*3-4转化成12+3*4-
  5     double calcExpr(string s);            //计算后缀表达式的值
  6 private:
  7     int getPriority(char ch);            //获取操作符的优先级
  8     bool isOperator(char ch);            //判断是否为操作符或者操作数
  9     double calc(double a,char ch, double b);
 10 };
 11 
 12 string ComputeExpr::transPosExpr(std::string s)
 13 {
 14     string ret;
 15     stack<char> stkOper;
 16     int len = s.length();
 17     for (int i=0; i<len; i++)
 18     {
 19         if (!isOperator(s[i]))    //如果是操作数,直接输出
 20         {
 21             ret += s[i];
 22         }
 23         else if (s[i]=='(')        //如果是'(',将它放入堆栈中
 24         {
 25             stkOper.push('(');
 26         }
 27         else if (s[i]==')')        //如果是')'
 28         {
 29             while(!stkOper.empty())        //不停地弹出堆栈中的内容,直到遇到'('
 30             {
 31                 char topChar = stkOper.top();
 32                 stkOper.pop();
 33                 if (topChar=='(')
 34                 {
 35                     break;
 36                 }
 37                 ret += topChar;        //将堆栈中弹出的内容放入
 38             }
 39         }
 40         else        //既不是'(',也不是')',是其它操作符,比如+, -, *, /之类的
 41         {        
 42             if (!stkOper.empty())
 43             {
 44                 do 
 45                 {
 46                     char topChar = stkOper.top();
 47                     stkOper.pop();
 48                     if (getPriority(s[i]) > getPriority(topChar))//如果栈顶元素的优先级小于读取到的操作符
 49                     {
 50                         stkOper.push(topChar);    //将栈顶元素放回堆栈
 51                         stkOper.push(s[i]);        //将读取到的操作符放回堆栈
 52                         break;
 53                     }
 54                     else        //如果栈顶元素的优先级比较高或者两者相等时
 55                     {
 56                         ret += topChar;
 57                         if (stkOper.empty())
 58                         {
 59                             stkOper.push(s[i]);    //将读取到的操作符压入堆栈中
 60                             break;
 61                         }
 62                     }
 63                 } 
 64                 while (!stkOper.empty());
 65             }
 66             else         //如果堆栈为空,就把操作符放入堆栈中
 67             {
 68                 stkOper.push(s[i]);
 69             }
 70         }
 71     }
 72     while(!stkOper.empty())        //将堆栈中剩下的操作符输出
 73     {
 74         ret += stkOper.top();
 75         stkOper.pop();
 76     }
 77     return ret;
 78 }
 79 
 80 double ComputeExpr::calcExpr(std::string s)
 81 {
 82     int len = s.length();
 83     stack<double> stk;
 84     for (int i=0; i<len; i++)
 85     {
 86         if (!isOperator(s[i]))    //如果是操作数,直接压入栈
 87         {
 88             stk.push(s[i]-'0');
 89         }
 90         else     //如果是操作符,就弹出两个数字来进行运算
 91         {
 92             double a = stk.top();
 93             stk.pop();
 94             double b = stk.top();
 95             stk.pop();
 96             double t = calc(b,s[i],a);
 97             stk.push(t);
 98         }
 99     }
100     return stk.top();
101 }
102 
103 int ComputeExpr::getPriority(char ch)
104 {
105     int priority = 0;
106     switch(ch)
107     {
108     case '+':
109         priority = 1;
110         break;
111     case '-':
112         priority = 1;
113         break;
114     case '*':
115         priority = 2;
116         break;
117     case '/':
118         priority = 2;
119         break;
120     default:
121         priority = 0;
122         break;
123     }
124     return priority;
125 }
126 
127 bool ComputeExpr::isOperator(char ch)
128 {
129     const int MaxOperatorNum = 6;
130     const char a[MaxOperatorNum] = {'+','-','*','/','(',')'};
131     for (int i=0; i<MaxOperatorNum; i++)
132     {
133         if (ch == a[i])
134         {
135             return true;
136         }
137     }
138     return false;
139 }    
140 
141 double ComputeExpr::calc(double a,char ch, double b)
142 {
143     double res;
144     switch(ch)
145     {
146     case '+':
147         res = a+b;
148         break;
149     case '-':
150         res = a-b;
151         break;
152     case '*':
153         res = a*b;
154         break;
155     case '/':
156         res = a/b;
157         break;
158     }
159     return res;
160 }

 

posted on 2012-09-21 19:00  深山中一小妖  阅读(185)  评论(0编辑  收藏  举报

导航