[算法 笔记]字符串表达式计算(简易版)

  题目:编写一个函数,计算字符串中表达式的值,参数中只包含计算符:+-*/等。例如,str=”10+50+2*6/3”,result=64

  解析:

  考虑算术表达式计算规则

  1.  同优先级操作符之间,从左到右计算;
  2. 高优先级操作符的计算要早于低优先级操作符的计算;
  3. 加减操作符优先级低于乘除操作符优先级;
  4. 括号内的算术表达式的优先级高于括号外的乘除操作符的优先级。

  利用两个辅助栈来存储结果。一个用于存储数值,一个用于存储操作符。考虑算术表达式的计算过程(从左往右计算,先计算高优先级操作符),因此表达式字符串逆序压入栈中。由于考虑栈存储的特点以及计算表达式的顺序问题,需要逆序的将数值和算术符压入到栈中。因此,需要首先将数值逆序,然后在将整个表达式逆序。

  考虑操作符优先级的处理问题:在计算过程将出现三种情况(用current_opr表示刚刚从栈中弹出的操作符,top_opr表示操作符栈中栈顶的操作符):

  1. current_opr的优先级等于top_opr的优先级;
  2. current_opr的优先级大于top_opr的优先级;
  3. current_opr的优先级小于top_opr的优先级。

  在上述三种情况中,第一种和第二种均情况不需要考虑,直接计算直到current_opr的优先级低于top_opr的优先级。

  现在来讨论第三种情况的处理过程,将current_opr从栈顶开始向栈底“冒泡”,一直到操作符的优先级等于current_opr才停止。在操作符移动的过程中,数值栈中的元素也需要进行同方向的“冒泡”处理,但是深度要比操作符多一个。因为目前考虑的操作符均是二元操作符,需要两个操作数来完成计算。

  例如,算式字符串为:”25 + 10*50*12”。遍历的结果为:

  数值栈:(digit_stackvalue_top=3

12

50

10

25

 

 

  操作符栈:(op_stackopr_top=1

‘*’

‘*’

 

 

 

 

  处理过程:由于current_opr = ‘+’,top_opr=’*’,priority(current_opr) < priority(top_opr),因此需要对current_opr操作符进行“冒泡”处理,一直到优先级与current_opr相同为止。

  调整后,数值栈:(digit_stackvalue_top=3

25

12

50

10

 

 

  调整后,操作符栈为:(op_stackopr_top=1

‘+’

‘*’

 

 

 

 

  当前,current_opr=’*’,top_opr=’*’,则priority(current_opr) == priority(top_opr),即符号第一种情况。

  在编程中,对于“冒泡”处理有两种形式:

  1. 首先将元素压入栈中,然后通过交换的形式来达到“冒泡”处理。

 1 for ( i = opr_top - 1; i > 0; --i )
 2 {
 3     if ( priority(op_stack[i]) < priority(op_stack[i-1]) )
 4         swap( op_stack, i, i - 1 );
 5     else
 6         break;
 7 } 
 8 
 9 for ( j = value_top - 1; j > i; --j )
10 {
11     swap( value_stack, j, j - 1 );
12 }

  2. 不将数值压入栈中,而是首先查找符合要求的“位置”,然后将元素插入。

 1 for ( i = opr_top; i > 0; --i )
 2 {
 3     if ( priority(op_stack[j-1]) > priority(current_opr) )
 4         op_stack[j] = op_stack[j-1];
 5     else
 6         break;
 7 }
 8 op_stack[i] = current_opr;
 9 ++opr_top;
10 
11 for ( j = value_top; j > i; --j )
12 {
13     value_stack[j] = value_stack[j - 1];
14 }
15 value_stack[j] = result;
16 ++value_top;

  完整程序的源码:

  1 #include <vector>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <iterator>
  5 #include <stdexcept>
  6 using namespace std;
  7 
  8 class stack_is_empty : public runtime_error
  9 {
 10 public:
 11     stack_is_empty( const string s )
 12     : runtime_error( s ){}
 13 };
 14 
 15 class divisor_is_zero: public runtime_error
 16 {
 17 public:
 18     divisor_is_zero( const string s )
 19     : runtime_error( s ) {}
 20 };
 21 
 22 
 23 /**< expression reversal */
 24 void expression_reversal( string &expr )
 25 {
 26     string::iterator iter = expr.begin();
 27     string::iterator tmp;
 28 
 29     while ( iter != expr.end() )
 30     {
 31         if ( *iter >= '0' && *iter <= '9' )
 32         {
 33             /**< value reversal */
 34             for ( tmp = iter; iter != expr.end()
 35                    && *iter >= '0' && *iter <= '9'; ++iter );
 36             reverse( tmp, iter );
 37         }
 38         else
 39             ++iter;
 40     }
 41 
 42     /**< expression reversal */
 43     reverse( expr.begin(), expr.end() );
 44 }
 45 
 46 /**< remove spaces of expression */
 47 void remove_space( string &orig_expr, string &expr )
 48 {
 49     string::iterator iter = orig_expr.begin();
 50 
 51     for ( ; iter != orig_expr.end() ; ++iter )
 52     {
 53         if ( *iter != ' ' )
 54             expr.push_back( *iter );
 55     }
 56 }
 57 
 58 /**< separation of value and operators. */
 59 void preprocess( string &orig_expr,
 60                 vector<int> &value_stack,
 61                 vector<char> &oper_stack )
 62 {
 63     string expr;
 64     remove_space( orig_expr, expr );
 65     expression_reversal( expr );
 66 
 67     string::iterator iter = expr.begin();
 68 
 69     while ( iter != expr.end() )
 70     {
 71         // push value into value_stack.
 72         if ( *iter >= '0' && *iter <= '9' )
 73         {
 74             int value = 0;
 75             while ( iter != expr.end()
 76                    && *iter >= '0' && *iter <= '9' )
 77             {
 78                 value *= 10;
 79                 value += ( *iter - '0' );
 80                 ++iter;
 81             }
 82 
 83             value_stack.push_back( value );
 84         }
 85         else
 86         {
 87             // push operator into oper_stack.
 88             oper_stack.push_back( *iter );
 89             ++iter;
 90         }
 91     }
 92 }
 93 
 94 /**< get priority of operator */
 95 int oper_priority( const char ch )
 96 {
 97     int flag = 0;
 98     if ( ch == '*' || ch == '/' )
 99         flag = 5;
100 
101     return flag;
102 }
103 
104 /**< compute value with operator */
105 int compute_value( int lhs, int rhs, char oper )
106 {
107     int value = 0;
108     switch( oper )
109     {
110     case '+': value = lhs + rhs; break;
111     case '-': value = lhs - rhs; break;
112     case '*': value = lhs * rhs; break;
113     case '/':
114         if ( rhs == 0 )
115             throw divisor_is_zero( "divisor is zero." );
116         value = lhs / rhs;
117         break;
118     default: break;
119     }
120 
121     return value;
122 }
123 
124 /**< compute value  */
125 int compute_expr( vector<int> &value, vector<char> &oper )
126 {
127     char current_oper = '\0';
128     int current_value = 0;
129 
130     if ( value.empty() || oper.empty() )
131     {
132         throw stack_is_empty( "Stack is empty." );
133         return -1;
134     }
135 
136     while ( value.empty() == false
137            && oper.empty() == false )
138     {
139         current_oper = oper.back(), oper.pop_back();
140 
141         if ( oper.empty()
142             || oper_priority( current_oper ) >= oper_priority( oper.back() )  )
143         {
144             int lhs = value.back();
145             value.pop_back();
146             int rhs = value.back();
147             value.pop_back();
148             current_value = compute_value( lhs, rhs, current_oper );
149             value.push_back( current_value );
150         }
151         else
152         {
153             /**< value and operators are moved to new place. */
154             oper.push_back( current_oper );
155             size_t last_index = oper.size() - 1;
156             for ( ; last_index > 0; --last_index  )
157             {
158                 if ( oper_priority( oper[last_index - 1] )
159                      <= oper_priority( current_oper ) )
160                     break;
161                 oper[last_index] = oper[last_index - 1];
162             }
163             oper[last_index] = current_oper;
164 
165             current_value = value.back();
166             for ( size_t j = value.size() - 1;
167                     j > last_index; --j )
168             {
169                 value[j] = value[j - 1];
170             }
171             value[last_index] = current_value;
172         }
173     }
174 
175     if ( oper.empty() )
176     {
177         current_value = value.front();
178     }
179 
180     return current_value;
181 }
182 
183 int main()
184 {
185     string str( " 50 - 20 + 5 * 6 / 2" );
186     vector<int> value;
187     vector<char> oper;
188     int result = 0;
189     preprocess( str, value, oper );
190 
191     result = compute_expr( value, oper );
192     cout << result << endl;
193 
194     return 0;
195 }
ComputeExpression

 

  简易版本不足之处

  1. 不能计算括号表达式
  2. 对负数不能有效的处理
  3. 不能有效计算大数
  4. 对表达式中符号以及括号的合法性检查
posted @ 2013-11-01 15:11  life91  阅读(989)  评论(0编辑  收藏  举报