题目:编写一个函数,计算字符串中表达式的值,参数中只包含计算符:+,-,*,/等。例如,str=”10+50+2*6/3”,result=64。
解析:
考虑算术表达式计算规则:
- 同优先级操作符之间,从左到右计算;
- 高优先级操作符的计算要早于低优先级操作符的计算;
- 加减操作符优先级低于乘除操作符优先级;
- 括号内的算术表达式的优先级高于括号外的乘除操作符的优先级。
利用两个辅助栈来存储结果。一个用于存储数值,一个用于存储操作符。考虑算术表达式的计算过程(从左往右计算,先计算高优先级操作符),因此表达式字符串逆序压入栈中。由于考虑栈存储的特点以及计算表达式的顺序问题,需要逆序的将数值和算术符压入到栈中。因此,需要首先将数值逆序,然后在将整个表达式逆序。
考虑操作符优先级的处理问题:在计算过程将出现三种情况(用current_opr表示刚刚从栈中弹出的操作符,top_opr表示操作符栈中栈顶的操作符):
- current_opr的优先级等于top_opr的优先级;
- current_opr的优先级大于top_opr的优先级;
- current_opr的优先级小于top_opr的优先级。
在上述三种情况中,第一种和第二种均情况不需要考虑,直接计算直到current_opr的优先级低于top_opr的优先级。
现在来讨论第三种情况的处理过程,将current_opr从栈顶开始向栈底“冒泡”,一直到操作符的优先级等于current_opr才停止。在操作符移动的过程中,数值栈中的元素也需要进行同方向的“冒泡”处理,但是深度要比操作符多一个。因为目前考虑的操作符均是二元操作符,需要两个操作数来完成计算。
例如,算式字符串为:”25 + 10*50*12”。遍历的结果为:
数值栈:(digit_stack,value_top=3)
12 |
50 |
10 |
25 |
|
|
操作符栈:(op_stack,opr_top=1)
‘*’ |
‘*’ |
|
|
|
|
处理过程:由于current_opr = ‘+’,top_opr=’*’,priority(current_opr) < priority(top_opr),因此需要对current_opr操作符进行“冒泡”处理,一直到优先级与current_opr相同为止。
调整后,数值栈:(digit_stack,value_top=3)
25 |
12 |
50 |
10 |
|
|
调整后,操作符栈为:(op_stack,opr_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;
完整程序的源码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 = '