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

  题目:编写一个函数,计算字符串中表达式的值,参数中只包含计算符:+-*/等。例如,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. 对表达式中符号以及括号的合法性检查

你可能感兴趣的:(字符串)