中缀表达式求解

问题描述:

      中缀表达式计算,只包含加减乘除以及括号,例如:

      2+3*4-5/2 = 11.5

      ((2+3*4)-5)/2 = 4.5

 

思路:

  1. 维护两个栈空间:数字栈与符号栈

  2. 注意入栈与出栈的规则,符号栈入栈时,根据符号优先级判断是否入栈或出栈。

          高优先级符号后入栈时直接放入即可,低优先级符号后入栈时先弹出高优先级符号,优先级如下:

          ( < +- < * / < )

    普通操作符弹出计算时,只进行一次pop_cal操作。

    右括号出栈时,必须循环计算至左括号出栈为止。

 

边界case:

  1. 分母为0,assert处理。

  2. 数字范围超出变量上下限。

 

知识点:

  1. 栈操作:围绕出栈入栈操作分解问题,分解成cal计算函数、push_xxx压栈操作、pop_cal出栈计算操作、push_check入栈检查优先级等几步,逻辑会更清晰。

  2. 字符处理:用stringstream简化处理逻辑,string -> float, float -> string,多次使用之间需要clear() & str(""),重置标识以及清空字符串两个操作。

 

难度:★★★★

  1. 代码量大

  2. 需要考虑的细节多:字符处理、边界case、符号优先级、右括号特殊处理

  3. 熟悉栈操作

  

 伪码:

  1 #include <stack>
  2 #include <string>
  3 #include <sstream>
  4 #include <iostream>
  5 #include <assert.h>
  6 #include <ctype.h>
  7 
  8 using namespace std;
  9 
 10 stack<string> nums; //数字栈
 11 stack<char> exps;   //操作符栈
 12 
 13 //压入数字栈
 14 void push_num(char exp, bool is_new)
 15 {
 16     if( is_new )
 17     {
 18         string new_num = string("") + exp;
 19         nums.push( new_num );
 20     }
 21     else
 22     {
 23         string top_num = nums.top();
 24         nums.pop();
 25         top_num += exp;
 26         nums.push( top_num );
 27     }
 28 }
 29 
 30 //得到优先级
 31 int get_priority(char exp)
 32 {
 33     switch( exp )
 34     {
 35         case '*':
 36             return 2;
 37         case '/':
 38             return 2;
 39         case '+':
 40             return 1;
 41         case '-':
 42             return 1;
 43         case '(':
 44             return 0;
 45         case ')':
 46             return -1;
 47     }
 48     return 0;
 49 }
 50 
 51 //检查入栈优先级
 52 bool push_check(char exp)
 53 {
 54     if( exps.size() == 0 )
 55     {
 56         return true;
 57     }
 58     int cur_prio = get_priority(exp);
 59     int top_prio = 3;
 60     char top_exp = exps.top();
 61     top_prio = get_priority(top_exp);
 62     if( cur_prio < top_prio )
 63     {
 64         return false;
 65     }
 66     return true;
 67 }
 68 
 69 //数字出栈
 70 void pop_nums(float &num1, float &num2)
 71 {
 72     stringstream ss;
 73     string num = nums.top();
 74     ss << num;
 75     ss >> num1;
 76     nums.pop();
 77     ss.clear();
 78     ss.str("");
 79     num = nums.top();
 80     ss << num;
 81     ss >> num2;
 82     nums.pop();
 83 }
 84 
 85 //出栈一次并计算结果,返回当前出栈操作符
 86 char pop_cal(float &res)
 87 {
 88     res = 0.0;
 89     char exp = exps.top();
 90     exps.pop();
 91     if( exp != '(' )
 92     {
 93         float num1, num2;
 94         pop_nums(num1, num2);
 95         switch( exp )
 96         {
 97             case '*':
 98                 res = num2 * num1;
 99                 break;
100             case '/':
101                 res = num2 / num1;
102                 break;
103             case '+':
104                 res = num2 + num1;
105                 break;
106             case '-':
107                 res = num2 - num1;
108                 break;
109         }
110     }
111     return exp;
112 }
113 
114 //压入操作符栈
115 void push_exp(char exp)
116 {
117     while( ! push_check(exp) )
118     {
119         float res;
120         char pop_exp = pop_cal(res);
121         if( pop_exp != '(' )
122         {
123             string num;
124             stringstream ss;
125             ss << res;
126             ss >> num;
127             nums.push( num );
128         }
129         if( exp == ')' && pop_exp == '(' )
130             break;
131     }
132     if( exp != ')' )
133     {
134         exps.push( exp );
135     }
136 }
137 
138 //主函数:计算中缀表达式
139 float cal_res(const string &express)
140 {
141     //是否新数字
142     bool new_num = true;
143     //循环读取表达式字符
144     for(size_t i = 0; i < express.size(); i++)      
145     {
146         //处理数字
147         if( isdigit( express[i] ) || express[i] == '.' )
148         {
149             //数字压栈
150             push_num(express[i], new_num);
151             new_num = false;
152         }
153         else
154         {
155             //操作符压栈
156             push_exp( express[i] );
157             new_num = true;
158         }
159     }
160     //循环出栈,计算结果
161     float res = 0.0;
162     while( exps.size() > 0 )
163     {
164         pop_cal( res );
165     }
166     return res;
167 }
168 
169 int main()
170 {
171     string expression = "(3.2+4.0/2.1)*5.0";
172     cout << cal_res( expression ) << endl;
173     return 0;
174 }
View Code

 

转载请注明引用自:

  http://www.cnblogs.com/breakthings/p/4049575.html 

 

  

posted @ 2014-10-25 10:24  breakthings  阅读(407)  评论(0编辑  收藏  举报