表达式求值,中缀后缀转换,表达式递归直接求值等相关算法的实现
当前算法都未考虑多个优先级的问题,仅仅考虑+,-,*,/与()
//expression.h
1 /*
2 * =====================================================================================
3 * Filename: expression.h
4 * Description:
5 * 各种与表达式相关的算法
6 * 如中缀转后缀
7 * 后缀表达式求值
8 * 中缀表达式递归求值
9 * =====================================================================================
10 */
11 #ifndef _EXPRESSION_H_
12 #define _EXPRESSION_H_
13 #include <string>
14 #include <stack>
15 #include <iostream>
16 #include <algorithm>
17 #include <sstream>
18 #include <vector>
19 #include <list>
20 #include <assert.h>
21
22 using namespace std;
23
24 namespace binary_tree {
25 //二叉树前置声明
26 template<typename T>
27 class BinaryTreeNode;
28
29 template<typename U, typename T>
30 class BinaryTree;
31
32 template<typename T>
33 class SimpleBinaryTreeNode;
34
35 template<typename U, typename T>
36 class SimpleBinaryTree;
37 }
38
39 namespace expression {
40
41 //typedef binary_tree::BinaryTreeNode<string> Node;
42 //typedef binary_tree::BinaryTree<string,Node> Tree;
43 typedef binary_tree::SimpleBinaryTreeNode<string> Node;
44 typedef binary_tree::SimpleBinaryTree<string,Node> Tree;
45
46 /*对外接口********************************************************/
47 //中缀表达式带括号转后缀,支持浮点
48 //用户输入有错误会识别出来报错,不做修正
49 bool Infix2Suffix(string infix_string, string &suffix_string);
50
51 //后缀表达式求值,注意后缀表达式是用" "隔开的
52 double EvaluateSuffixString(const string &suffix_string);
53
54 //判断给出的中缀表达式是否正确,括号匹配正确,无特殊字符,否则报错
55 bool InfixStringNormallize(string &infix_string);
56
57 //中缀表达式直接求值,要求中缀表达式格式正确,且按空格隔开
58 //递归求解
59 double EvaluateInfixString(const string& infix_string);
60 /****************************************************************/
61
62
63 template <class T>
64 T ConvertString2Num(const std::string &s) {
65 T value;
66 std::stringstream ss(s);
67 ss >> value;
68 return value;
69 }
70 //template <class T>
71 //void ConvertString2Num(const std::string &s, T &value) {
72 // std::stringstream ss(s);
73 // ss >> value;
74 //}
75
76 //当前只考虑+ - * / 4种运算符号
77 //+ - 优先级为 0
78 //* / 优先级为 1
79 int Priority(const char op);
80
81 //分析是否为数字,判断一个字符
82 inline bool IsDigit(const char input);
83 //分析整个string是否为数字,头一位是数字就是数字或者头一位-,-3
84 inline bool IsNum(const string& s);
85
86 double EvaluateInfixStringHelp(const vector<string> &vec);
87 //找到根节点后将原数组分成左右两部分供递归调用
88 void SplitVec(const vector<string> &vec, vector<string> &vec_left,
89 vector<string> &vec_right, char &op);
90
91 //用vector下标的这个版本有bug TODO (3+2)*4+2
92 double EvaluateInfixStringHelp(const vector<string> &vec, int begin, int end);
93 void SplitVec(const vector<string> &vec,
94 const int begin, const int end,
95 int &left_begin, int &left_end,
96 int &right_begin, int &right_end,
97 char &op);
98
99 //using list
100 double EvaluateInfixString2(const string& infix_string);
101 double EvaluateInfixStringHelp2(list<string> &l);
102 void SplitList(list<string> &l, list<string> &list_left,
103 list<string> &list_right, char &op);
104
105
106 //由标准中缀表达式建立表达式二叉树
107 void CreateExpressionBinaryTree(const string& infix_string,
108 Tree &binary_tree);
109 Node* CreateExpressionBinaryTreeHelp(
110 const vector<string> &vec);
111
112 } //end of namespace expression
113 #endif //end of _EXPRESSION_H_
2 * =====================================================================================
3 * Filename: expression.h
4 * Description:
5 * 各种与表达式相关的算法
6 * 如中缀转后缀
7 * 后缀表达式求值
8 * 中缀表达式递归求值
9 * =====================================================================================
10 */
11 #ifndef _EXPRESSION_H_
12 #define _EXPRESSION_H_
13 #include <string>
14 #include <stack>
15 #include <iostream>
16 #include <algorithm>
17 #include <sstream>
18 #include <vector>
19 #include <list>
20 #include <assert.h>
21
22 using namespace std;
23
24 namespace binary_tree {
25 //二叉树前置声明
26 template<typename T>
27 class BinaryTreeNode;
28
29 template<typename U, typename T>
30 class BinaryTree;
31
32 template<typename T>
33 class SimpleBinaryTreeNode;
34
35 template<typename U, typename T>
36 class SimpleBinaryTree;
37 }
38
39 namespace expression {
40
41 //typedef binary_tree::BinaryTreeNode<string> Node;
42 //typedef binary_tree::BinaryTree<string,Node> Tree;
43 typedef binary_tree::SimpleBinaryTreeNode<string> Node;
44 typedef binary_tree::SimpleBinaryTree<string,Node> Tree;
45
46 /*对外接口********************************************************/
47 //中缀表达式带括号转后缀,支持浮点
48 //用户输入有错误会识别出来报错,不做修正
49 bool Infix2Suffix(string infix_string, string &suffix_string);
50
51 //后缀表达式求值,注意后缀表达式是用" "隔开的
52 double EvaluateSuffixString(const string &suffix_string);
53
54 //判断给出的中缀表达式是否正确,括号匹配正确,无特殊字符,否则报错
55 bool InfixStringNormallize(string &infix_string);
56
57 //中缀表达式直接求值,要求中缀表达式格式正确,且按空格隔开
58 //递归求解
59 double EvaluateInfixString(const string& infix_string);
60 /****************************************************************/
61
62
63 template <class T>
64 T ConvertString2Num(const std::string &s) {
65 T value;
66 std::stringstream ss(s);
67 ss >> value;
68 return value;
69 }
70 //template <class T>
71 //void ConvertString2Num(const std::string &s, T &value) {
72 // std::stringstream ss(s);
73 // ss >> value;
74 //}
75
76 //当前只考虑+ - * / 4种运算符号
77 //+ - 优先级为 0
78 //* / 优先级为 1
79 int Priority(const char op);
80
81 //分析是否为数字,判断一个字符
82 inline bool IsDigit(const char input);
83 //分析整个string是否为数字,头一位是数字就是数字或者头一位-,-3
84 inline bool IsNum(const string& s);
85
86 double EvaluateInfixStringHelp(const vector<string> &vec);
87 //找到根节点后将原数组分成左右两部分供递归调用
88 void SplitVec(const vector<string> &vec, vector<string> &vec_left,
89 vector<string> &vec_right, char &op);
90
91 //用vector下标的这个版本有bug TODO (3+2)*4+2
92 double EvaluateInfixStringHelp(const vector<string> &vec, int begin, int end);
93 void SplitVec(const vector<string> &vec,
94 const int begin, const int end,
95 int &left_begin, int &left_end,
96 int &right_begin, int &right_end,
97 char &op);
98
99 //using list
100 double EvaluateInfixString2(const string& infix_string);
101 double EvaluateInfixStringHelp2(list<string> &l);
102 void SplitList(list<string> &l, list<string> &list_left,
103 list<string> &list_right, char &op);
104
105
106 //由标准中缀表达式建立表达式二叉树
107 void CreateExpressionBinaryTree(const string& infix_string,
108 Tree &binary_tree);
109 Node* CreateExpressionBinaryTreeHelp(
110 const vector<string> &vec);
111
112 } //end of namespace expression
113 #endif //end of _EXPRESSION_H_
//expression.cc
1 #include "expression.h"
2 #include "binary_tree.h"
3 using std::stack;
4 using std::string;
5 using std::cout;
6 using std::endl;
7 namespace expression {
8
9 //op + - * / (
10 //num data and )
11 //用于检测输入是否正确,不是传统的数字,操作符定义
12 enum State{op,num};
13
14 //string 转成double等任意类型
15 //当前只考虑+ - * / 4种运算符号
16 //+ - 优先级为 0
17 //* / 优先级为 1
18 int Priority(const char op) {
19 int priority;
20 switch(op) {
21 case '+': case '-':
22 priority = 0;
23 break;
24 case '*': case '/':
25 priority = 1;
26 break;
27 case '(':
28 priority = -1; // we need it to stop pop like (3 + 4 + 5),监视哨,到了(停下
29 break;
30 default:
31 cout << "error" << endl;
32 break;
33 }
34 return priority;
35 }
36
37 //分析是否为数字
38 inline bool IsDigit(const char input) {
39 return input >= '0' && input <= '9';
40 }
41
42 //中缀表达式带括号转后缀,支持浮点
43 //用户输入有错误会识别出来报错,不做修正
44 //允许用户输入冗余的初始括号,(a+b),视为正确输入
45 //同时处理是时对于没有最外层括号的也加上便于处理
46 //判断过程,对于运算符前面的比栈里的priority小或者相等的运算符要出栈,被计算
47 //然后当前的入栈
48 //对于(入栈
49 //对于),将栈里的运算符都pop,被计算,将( pop
50 //对于数字,直接输出
51 //表达式正确性判断,判断了括号是否匹配,利用栈
52 //直接判断有无错误输入字符
53 //通过状态位,op,num判断是否连续输入数字,或者操作符错误
54 //或者(前输入了),数字错误
55 //或者)前输入了操作符,(错误
56 //括号)视为num,要求前面也为num
57 //括号(视为op,要求前面也为op
58 //数字视为num,要求前面为op
59 //运算符视为op,要求前面为num
60 bool Infix2Suffix(string infix_string, string &suffix_string){
61 stack<char> s; //notice we use char not string because elements of string is char
62 suffix_string.clear();
63 //预处理强制最外层加括号 方便统一处理,这样不需要最后的多余一步栈内处理
64 infix_string = '(' + infix_string;
65 infix_string += ')';
66
67 //转换核心部分
68 int len = infix_string.length();
69 State state = op; //开始第一个为(,状态为op
70 for (int i = 0; i < len; i++) {
71 //处理数字情况 遇到一个数字就把它整个数找到,然后处理下一个字符op
72 //要考虑到 3.34浮点数的处理,要考虑到-3.34负数的处理数字处理
73 //的共同特点是最后结束位一定是数字
74 int dot_flag = 0; //允许处理浮点数allow only one . like 3.332
75 int i2 = i;
76 while (i < len &&
77 (IsDigit(infix_string[i]) ||
78 (i < len -1 && infix_string[i]== '-' //-3被视为数字处理
79 && IsDigit(infix_string[i + 1])))) {
80 suffix_string += infix_string[i];
81 i++;
82 if (i < len && !dot_flag && infix_string[i] == '.') { //浮点数字处理
83 suffix_string += infix_string[i];
84 i++;
85 dot_flag = 1;
86 }
87 }
88
89 if (i > i2 && IsDigit(infix_string[i-1])) { // i>i2则表明刚处理了数字
90 suffix_string += ' ';
91 if (state != op) { //数字前面应该是运算符或者(
92 suffix_string.clear();
93 return false;
94 }
95 state = num;
96 } else if (i > i2 && dot_flag == 1) {
97 return false; //case like 3.
98 }
99
100
101 if (i == len) //we have done,(处理完最后一个数)
102 break;
103
104 //处理操作符,非数字情况
105 switch(infix_string[i]) {
106 case '(':
107 if (state != op) // (前面应该是运算符符或者(,左括号按照op处理
108 return false;
109 //state = op;
110 s.push('(');
111 break;
112 case ')':
113 if (state != num) // )前面应该是数字或者),右括号按照num处理
114 return false;
115 //state = num;
116 while(!s.empty() && s.top() != '(') { //如果能确保输入括号的正确性,则不需要!s.empty()的判断
117 suffix_string += s.top();
118 suffix_string += ' ';
119 s.pop();
120 }
121 if (s.empty()) //括号不匹配,缺左括号
122 return false;
123 s.pop(); // pop '('
124 break;
125 case '+': case '-': case '*': case '/':
126 if (state != num) //运算符前面应该是数字或者)
127 return false;
128 state = op;
129 while(!s.empty() && s.top() != '(' &&
130 (Priority(infix_string[i]) <= Priority(s.top()))) { //如果能确保输入括号的正确性,则不需要!s.empty()的判断
131 suffix_string += s.top();
132 suffix_string += ' ';
133 s.pop();
134 }
135 s.push(infix_string[i]);
136 break;
137 case ' ': case '\t': case '\r': //空格允许,但不处理, linux读的行是带\r的
138 break;
139 default: //遇到意外字符,输入有误
140 cout << "Unexpeced input, error, check your input" << endl;
141 return false;
142 }
143 }
144 if (state != num) //容易忽略,表达式尾部需要是数字
145 return false;
146 if (!s.empty()) //括号不匹配,左括号多,注意如果没有预处理的加最外面的括号,则需要继续pop出栈的
147 return false;
148 //去掉最后的空格
149 suffix_string.erase(string::size_type(suffix_string.size()-1), string::size_type(1));
150 //OK,finally convert sucessfully
151 return true;
152 }
153
154
155 inline bool IsNum(const string& s) {
156 return IsDigit(s[0]) || (s[0] == '-' && IsDigit(s[1]));
157 }
158
159 //后缀表达式求值,注意后缀表达式是用" "隔开的
160 double EvaluateSuffixString(const string &suffix_string) {
161 stringstream ss(suffix_string);
162 double elem, p, p1, p2;
163 string sub_str;
164 stack<double> s;
165 while(getline(ss,sub_str,' ')) {
166 //处理数字
167 if (IsNum(sub_str)) {
168 elem = ConvertString2Num<double>(sub_str);
169 s.push(elem);
170 } else { //运算符
171 p2 = s.top();
172 s.pop();
173 p1 = s.top();
174 s.pop();
175 switch(sub_str[0]) {
176 case '+':
177 p = p1 + p2;
178 break;
179 case '-':
180 p = p1 - p2;
181 break;
182 case '*':
183 p = p1 * p2;
184 break;
185 case '/':
186 p = p1 / p2;
187 break;
188 default:
189 cout << "error operator" << endl;
190 break;
191 }
192 s.push(p);
193 }
194 }
195 return s.top();
196 }
197
198 //判断给出的中缀表达式是否正确,括号匹配正确,无特殊字符,否则报错
199 //如果是正确的化转换成标准带空格的中缀表达式,如果有最外层括号,去掉
200 //(3+2) 视为正确的输入但是转换为3 + 2
201 //(3+2)*(4+6) 注意这样是没有最外层括号的
202 bool InfixStringNormallize(string &infix_string) {
203 //如果有最外层的括号,去掉它
204 int len = infix_string.length();
205 string infix_string2; //临时转换结果
206
207 stack<int> s;
208 int sum = 0; //标记是第几个(, 当如果末尾是)并且将0号(pop出来则有最外层括号
209 int pre_sum = -1; //标记当前是哪个标号的(出栈
210 State state = op; //开始第一个为数字或者左括号,期待前面是op
211 bool flag_bracket = false; //是否有最外层的括号:
212
213 for (int i = 0; i < len; i++) {
214 int dot_flag = 0; //允许处理浮点数allow only one . like 3.332
215 int i2 = i;
216 while (i < len &&
217 (IsDigit(infix_string[i]) ||
218 (i < len -1 && infix_string[i]== '-' //-3被视为数字处理
219 && IsDigit(infix_string[i + 1])))) {
220 infix_string2 += infix_string[i];
221 i++;
222 if (i < len && !dot_flag && infix_string[i] == '.') { //浮点数字处理
223 infix_string2 += infix_string[i];
224 i++;
225 dot_flag = 1;
226 }
227 }
228
229 if (i > i2 && IsDigit(infix_string[i-1])) { // i>i2则表明刚处理了数字
230 infix_string2 += ' ';
231 if (state != op) { //数字前面应该是运算符或者(
232 infix_string2.clear();
233 return false;
234 }
235 state = num;
236 } else if (i > i2 && dot_flag == 1) {
237 return false; //case like 3.
238 }
239
240
241 if (i == len) //we have done,(处理完最后一个数)
242 break;
243
244 //处理操作符,非数字情况
245 switch(infix_string[i]) {
246 case '(':
247 if (state != op) // (前面应该是运算符符或者(,左括号按照op处理
248 return false;
249 //state = op;
250 s.push(sum++);
251 infix_string2 += '(';
252 infix_string2 += ' ';
253 break;
254 case ')':
255 if (state != num) // )前面应该是数字或者),右括号按照num处理
256 return false;
257 //state = num;
258 if(s.empty()) //无左括号匹配
259 return false;
260 infix_string2 += ')';
261 infix_string2 += ' ';
262 pre_sum = s.top();
263 s.pop();
264 break;
265 case '+': case '-': case '*': case '/':
266 if (state != num) //运算符前面应该是数字或者)
267 return false;
268 state = op;
269 infix_string2 += infix_string[i];
270 infix_string2 += ' ';
271 break;
272 case ' ': case '\t': case '\r': //空格允许,但不处理, linux读的行是带\r的
273 break;
274 default: //遇到意外字符,输入有误
275 cout << "Unexpeced input, error, check your input" << endl;
276 return false;
277 }
278 }
279 if (state != num) //容易忽略,表达式尾部需要是数字
280 return false;
281 if (!s.empty()) //(未被匹配完
282 return false;
283 //注意infix_string2最后有一个多余的空格
284 int start = 0;
285 int end = infix_string2.size() - 2;
286 //最左边是(,最右边是),并且(是最后一个出栈的(,就是最外层有(),需要去除的情况
287 if (infix_string2[start] == '(' && infix_string2[end] == ')' && pre_sum == 0 )
288 flag_bracket = true;
289 if (flag_bracket) //去括号,注意空格
290 infix_string.assign(infix_string2.begin() + 2, infix_string2.end() - 3);
291 else //不需要去括号,但注意末尾的多余空格
292 infix_string.assign(infix_string2.begin(), infix_string2.end()- 1);
293 return true;
294 }
295
296 //中缀表达式直接求值,要求中缀表达式格式正确,且按空格隔开
297 //递归求解
298 //首先找根节点,根节点是括号外面的最后一个 +/-,或者*/ 如果括号外面没有+ -
299 //开始的时候处理成没有最外面括号的,但后面要再保证不出现
300 //忽略了括号问题,晕了,当出现例如(3+2)的时候,需要破括号
301 //唉,什么时候能够一遍写对呢? :) 思维不够缜密全面
302 //注意这种情况 (3+2)*(4+5) + 3 不能去成3+2)*(4+5
303 //所以从右向左扫描字符串
304 // TODO 当前函数只考虑了存在 + - 和 * /两种优先级的情况
305
306 //找根节点,本质上是找优先级最低的前提下最靠近右边的,如果有多个优先级,代码需要重写
307 //分裂可以修改函数改为只用下标标示分裂后的vec不需要真的assign,但可读性差
308 //或者改为list分裂 TODO 当前递归深度为d,就会用到d*(vec.size())的空间,每次向下都要新开vec.szie()的vec
309 //当前,可读最好,性能最差
310 //用下标递归,可读最差,性能最好
311 //用list 都居中
312
313
314 //注意这里用的end 指向最后一个元素
315 //而不是像vector end()指向末尾后面的元素
316 void SplitVec(const vector<string> &vec,
317 const int begin, const int end,
318 int &left_begin, int &left_end,
319 int &right_begin, int &right_end,
320 char &op) {
321 int pos = -1;
322 int candidate_pos = -1;
323 bool visited = false; //是否已经遇到过* /
324 stack<int> s; //s空表示在括号外部,每次入栈值+1
325 int sum = 0; //sum = 0表示入的是第一个括号,如果该括号最后才被出栈,则证明有最外()需要去除
326 int pre_sum = -1; //别忘了,因为*/ 是暂时人选,后面继续变化,但是如果最终选择,需要恢复其所有信息,包括最外括号信息
327 int pre_sum_candidate = -1;
328 char candidate_op;
329 bool left_flag = false; //是否有最外括号要去掉
330 bool right_flag = false;
331 //从右向左扫描数组
332 for (int i = end; i >= begin; i--) {
333 if (IsNum(vec[i]))
334 continue;
335 switch(vec[i][0]) {
336 case ')':
337 s.push(sum++);
338 break;
339 case '(':
340 pre_sum = s.top();
341 s.pop();
342 break;
343 case '+': case '-':
344 if (s.empty()) {
345 pos = i;
346 op = vec[i][0];
347 }
348 break;
349 case '*': case '/':
350 if (s.empty() && !visited) {
351 candidate_pos = i;
352 candidate_op = vec[i][0];
353 visited = true;
354 pre_sum_candidate = pre_sum;
355 }
356 break;
357 default:
358 cout << "error operator" << endl;
359 break;
360 }
361 if (pos != -1) //已经遇到括号外面的+ -了结束
362 break;
363 }
364
365 if (pos == -1) {
366 pos = candidate_pos;
367 op = candidate_op;
368 pre_sum = pre_sum_candidate;
369 }
370 if (vec[pos+1][0] == '(' && vec[end][0] == ')' && pre_sum == 0)
371 right_flag = true;
372 sum = 0;
373 pre_sum = -1;
374 //破括号!否则所有的符号都在括号内,无法继续了
375 if (vec[begin][0] == '(' && vec[pos-1][0] == ')') {
376 for (int i = begin; i < pos; i++) {
377 if (vec[i][0] == '(')
378 s.push(sum++);
379 if (vec[i][0] == ')') {
380 pre_sum = s.top();
381 s.pop();
382 }
383 }
384 if (pre_sum == 0)
385 left_flag = true;
386 }
387
388 // write the result
389 if (left_flag) {
390 left_begin = begin + 1;
391 left_end = pos - 2;
392 } else {
393 left_begin = begin;
394 left_end = pos - 1;
395 }
396
397 if (right_flag) {
398 right_begin = pos + 2;
399 right_end = end - 1;
400 } else {
401 right_begin = pos + 1;
402 right_end = end;
403 }
404
405 }
406 void SplitVec(const vector<string> &vec, vector<string> &vec_left,
407 vector<string> &vec_right, char &op) {
408 assert(vec.size() >= 3); //at least 3 + 2 using 3 space
409 int pos = -1;
410 int candidate_pos = -1;
411 bool visited = false; //是否已经遇到过* /
412 stack<int> s; //s空表示在括号外部,每次入栈值+1
413 int sum = 0; //sum = 0表示入的是第一个括号,如果该括号最后才被出栈,则证明有最外()需要去除
414 int pre_sum = -1; //别忘了,因为*/ 是暂时人选,后面继续变化,但是如果最终选择,需要恢复其所有信息,包括最外括号信息
415 int pre_sum_candidate = -1;
416 char candidate_op;
417 bool left_flag = false; //是否有最外括号要去掉
418 bool right_flag = false;
419 //从右向左扫描数组
420 for (int i = vec.size() - 1; i >= 0; i--) {
421 if (IsNum(vec[i]))
422 continue;
423 switch(vec[i][0]) {
424 case ')':
425 s.push(sum++);
426 break;
427 case '(':
428 pre_sum = s.top();
429 s.pop();
430 break;
431 case '+': case '-':
432 if (s.empty()) {
433 pos = i;
434 op = vec[i][0];
435 }
436 break;
437 case '*': case '/':
438 if (s.empty() && !visited) {
439 candidate_pos = i;
440 candidate_op = vec[i][0];
441 visited = true;
442 pre_sum_candidate = pre_sum;
443 }
444 break;
445 default:
446 cout << "error operator" << endl;
447 break;
448 }
449 if (pos != -1) //已经遇到括号外面的+ -了结束
450 break;
451 }
452
453 if (pos == -1) {
454 pos = candidate_pos;
455 op = candidate_op;
456 pre_sum = pre_sum_candidate;
457 }
458 if (vec[pos+1][0] == '(' && vec[vec.size()-1][0] == ')' && pre_sum == 0)
459 right_flag = true;
460 sum = 0;
461 pre_sum = -1;
462 //破括号!否则所有的符号都在括号内,无法继续了
463 if (vec[0][0] == '(' && vec[pos-1][0] == ')') {
464 for (int i = 0; i < pos; i++) {
465 if (vec[i][0] == '(')
466 s.push(sum++);
467 if (vec[i][0] == ')') {
468 pre_sum = s.top();
469 s.pop();
470 }
471 }
472 if (pre_sum == 0)
473 left_flag = true;
474 }
475 if (left_flag)
476 vec_left.assign(vec.begin() + 1, vec.begin() + pos - 1);
477 else
478 vec_left.assign(vec.begin(), vec.begin() + pos);
479 if (right_flag)
480 vec_right.assign(vec.begin() + pos + 2, vec.end() - 1);
481 else
482 vec_right.assign(vec.begin() + pos + 1, vec.end());
483 }
484
485 double EvaluateInfixStringHelp(const vector<string> &vec, int begin, int end) {
486 if (begin == end) {
487 return ConvertString2Num<double>(vec[begin]);
488 }
489
490 int left_begin, left_end, right_begin, right_end;
491 char op;
492
493 SplitVec(vec, begin, end,
494 left_begin, left_end,
495 right_begin, right_end, op);
496
497 switch(op) {
498 case '+':
499 return EvaluateInfixStringHelp(vec, left_begin, left_end) +
500 EvaluateInfixStringHelp(vec, right_begin, right_end);
501 break;
502 case '-':
503 return EvaluateInfixStringHelp(vec, left_begin, left_end) -
504 EvaluateInfixStringHelp(vec, right_begin, right_end);
505 break;
506 case '*':
507 return EvaluateInfixStringHelp(vec, left_begin, left_end) *
508 EvaluateInfixStringHelp(vec, right_begin, right_end);
509 break;
510 case '/':
511 return EvaluateInfixStringHelp(vec, left_begin, left_end) /
512 EvaluateInfixStringHelp(vec, right_begin, right_end);
513 break;
514 default:
515 break;
516 }
517
518 }
519 double EvaluateInfixStringHelp(const vector<string> &vec) {
520 //递归出口,只有一个数字
521 if (vec.size() == 1)
522 return ConvertString2Num<double>(vec[0]);
523
524 vector<string> vec_left, vec_right;
525 char op; //根的内容
526
527 SplitVec(vec, vec_left, vec_right, op);
528
529 switch(op) {
530 case '+':
531 return EvaluateInfixStringHelp(vec_left) +
532 EvaluateInfixStringHelp(vec_right);
533 break;
534 case '-':
535 return EvaluateInfixStringHelp(vec_left) -
536 EvaluateInfixStringHelp(vec_right);
537 break;
538 case '*':
539 return EvaluateInfixStringHelp(vec_left) *
540 EvaluateInfixStringHelp(vec_right);
541 break;
542 case '/':
543 return EvaluateInfixStringHelp(vec_left) /
544 EvaluateInfixStringHelp(vec_right);
545 break;
546 default:
547 break;
548 }
549 }
550
551 //要求执行之前infix_string 已经被normalize,
552 //空格间隔,没有最外层括号
553 double EvaluateInfixString(const string& infix_string) {
554 stringstream ss(infix_string);
555 string sub_str;
556 vector<string> vec;
557 // TODO how to improve below
558 while(getline(ss,sub_str,' '))
559 vec.push_back(sub_str);
560 // return EvaluateInfixStringHelp(vec);
561 return EvaluateInfixStringHelp(vec, 0, vec.size() - 1);
562 }
563
564 double EvaluateInfixString2(const string& infix_string) {
565 stringstream ss(infix_string);
566 string sub_str;
567 list<string> l;
568 while(getline(ss,sub_str,' '))
569 l.push_back(sub_str);
570 return EvaluateInfixStringHelp2(l);
571 }
572 double EvaluateInfixStringHelp2(list<string> &l) {
573 //递归出口,只有一个数字
574 if (l.size() == 1)
575 return ConvertString2Num<double>(*(l.begin()));
576
577 list<string> list_left, list_right;
578 char op; //根的内容
579
580 SplitList(l, list_left, list_right, op);
581
582 switch(op) {
583 case '+':
584 return EvaluateInfixStringHelp2(list_left) +
585 EvaluateInfixStringHelp2(list_right);
586 break;
587 case '-':
588 return EvaluateInfixStringHelp2(list_left) -
589 EvaluateInfixStringHelp2(list_right);
590 break;
591 case '*':
592 return EvaluateInfixStringHelp2(list_left) *
593 EvaluateInfixStringHelp2(list_right);
594 break;
595 case '/':
596 return EvaluateInfixStringHelp2(list_left) /
597 EvaluateInfixStringHelp2(list_right);
598 break;
599 default:
600 break;
601 }
602
603 }
604 void SplitList(list<string> &l, list<string> &list_left, list<string> &list_right, char &op) {
605 assert(l.size() >= 3); //at least 3 + 2 using 3 space
606 bool visited = false; //是否已经遇到过* /
607 stack<int> s; //s空表示在括号外部,每次入栈值+1
608 int sum = 0; //sum = 0表示入的是第一个括号,如果该括号最后才被出栈,则证明有最外()需要去除
609 int pre_sum = -1; //别忘了,因为*/ 是暂时人选,后面继续变化,但是如果最终选择,需要恢复其所有信息,包括最外括号信息
610 int pre_sum_candidate = -1;
611 char candidate_op;
612 bool left_flag = false; //是否有最外括号要去掉
613 bool right_flag = false;
614 //从右向左扫描数组
615 list<string>::iterator iter, pos_iter, candidate_pos_iter;
616 pos_iter = candidate_pos_iter = --l.begin();
617
618 for (iter = --l.end(); iter != --l.begin(); --iter) {
619 if (IsNum((*iter)))
620 continue;
621 switch((*iter)[0]) {
622 case ')':
623 s.push(sum++);
624 break;
625 case '(':
626 pre_sum = s.top();
627 s.pop();
628 break;
629 case '+': case '-':
630 if (s.empty()) {
631 pos_iter = iter;
632 op = (*iter)[0];
633 }
634 break;
635 case '*': case '/':
636 if (s.empty() && !visited) {
637 candidate_pos_iter = iter;
638 candidate_op = (*iter)[0];
639 visited = true;
640 pre_sum_candidate = pre_sum;
641 }
642 break;
643 default:
644 cout << "error operator" << endl;
645 break;
646 }
647 if (pos_iter != --l.begin()) //已经遇到括号外面的+ -了结束
648 break;
649 }
650
651 if (pos_iter == --l.begin()) {
652 pos_iter = candidate_pos_iter;
653 op = candidate_op;
654 pre_sum = pre_sum_candidate;
655 }
656
657 iter = pos_iter;
658 if (((*(++iter)))[0] == '(' && (*(--l.end()))[0] == ')' && pre_sum == 0)
659 right_flag = true;
660 sum = 0;
661 pre_sum = -1;
662 iter = pos_iter;
663 //破括号!否则所有的符号都在括号内,无法继续了
664 if ((*(l.begin()))[0] == '(' && (*(--iter))[0] == ')') {
665 for (iter = l.begin(); iter != pos_iter; iter++) {
666 if ((*iter)[0] == '(')
667 s.push(sum++);
668 if ((*iter)[0] == ')') {
669 pre_sum = s.top();
670 s.pop();
671 }
672 }
673 if (pre_sum == 0)
674 left_flag = true;
675 }
676
677 if (left_flag) {
678 iter = pos_iter;
679 --iter;
680 list_left.splice(list_left.end(), l, ++l.begin(), iter);
681 } else {
682 list_left.splice(list_left.end(), l, l.begin(), pos_iter);
683 }
684
685 iter = pos_iter;
686 if (right_flag) {
687 iter++;
688 iter++;
689 list_right.splice(list_right.end(), l, iter, --l.end());
690 } else {
691 iter++;
692 list_right.splice(list_right.end(), l, iter, l.end());
693 }
694 }
695
696 void CreateExpressionBinaryTree(const string& infix_string,
697 Tree &binary_tree) {
698 if (!binary_tree.IsEmpty())
699 binary_tree.DeleteBinaryTree(binary_tree.root());
700
701 //string内容按" "分开后存到vec中
702 stringstream ss(infix_string);
703 string sub_str;
704 vector<string> vec;
705 while(getline(ss,sub_str,' '))
706 vec.push_back(sub_str);
707 binary_tree.set_root(CreateExpressionBinaryTreeHelp(vec));
708 }
709
710 Node * CreateExpressionBinaryTreeHelp(
711 const vector<string> &vec) {
712 //递归出口,只有一个数字
713 if (vec.size() == 1)
714 return new Node(vec[0]);
715 vector<string> vec_left, vec_right;
716 char op;
717
718 SplitVec(vec, vec_left, vec_right, op);
719
720 //不能 string(char) 从类型‘char’到类型‘const char*’的转换无效
721 string op_string;
722 op_string += op;
723 Node * pnode = new Node(op_string);
724 pnode->set_left(CreateExpressionBinaryTreeHelp(vec_left));
725 pnode->set_right(CreateExpressionBinaryTreeHelp(vec_right));
726 return pnode;
727 }
728
729
730 } //end of namespace expression
2 #include "binary_tree.h"
3 using std::stack;
4 using std::string;
5 using std::cout;
6 using std::endl;
7 namespace expression {
8
9 //op + - * / (
10 //num data and )
11 //用于检测输入是否正确,不是传统的数字,操作符定义
12 enum State{op,num};
13
14 //string 转成double等任意类型
15 //当前只考虑+ - * / 4种运算符号
16 //+ - 优先级为 0
17 //* / 优先级为 1
18 int Priority(const char op) {
19 int priority;
20 switch(op) {
21 case '+': case '-':
22 priority = 0;
23 break;
24 case '*': case '/':
25 priority = 1;
26 break;
27 case '(':
28 priority = -1; // we need it to stop pop like (3 + 4 + 5),监视哨,到了(停下
29 break;
30 default:
31 cout << "error" << endl;
32 break;
33 }
34 return priority;
35 }
36
37 //分析是否为数字
38 inline bool IsDigit(const char input) {
39 return input >= '0' && input <= '9';
40 }
41
42 //中缀表达式带括号转后缀,支持浮点
43 //用户输入有错误会识别出来报错,不做修正
44 //允许用户输入冗余的初始括号,(a+b),视为正确输入
45 //同时处理是时对于没有最外层括号的也加上便于处理
46 //判断过程,对于运算符前面的比栈里的priority小或者相等的运算符要出栈,被计算
47 //然后当前的入栈
48 //对于(入栈
49 //对于),将栈里的运算符都pop,被计算,将( pop
50 //对于数字,直接输出
51 //表达式正确性判断,判断了括号是否匹配,利用栈
52 //直接判断有无错误输入字符
53 //通过状态位,op,num判断是否连续输入数字,或者操作符错误
54 //或者(前输入了),数字错误
55 //或者)前输入了操作符,(错误
56 //括号)视为num,要求前面也为num
57 //括号(视为op,要求前面也为op
58 //数字视为num,要求前面为op
59 //运算符视为op,要求前面为num
60 bool Infix2Suffix(string infix_string, string &suffix_string){
61 stack<char> s; //notice we use char not string because elements of string is char
62 suffix_string.clear();
63 //预处理强制最外层加括号 方便统一处理,这样不需要最后的多余一步栈内处理
64 infix_string = '(' + infix_string;
65 infix_string += ')';
66
67 //转换核心部分
68 int len = infix_string.length();
69 State state = op; //开始第一个为(,状态为op
70 for (int i = 0; i < len; i++) {
71 //处理数字情况 遇到一个数字就把它整个数找到,然后处理下一个字符op
72 //要考虑到 3.34浮点数的处理,要考虑到-3.34负数的处理数字处理
73 //的共同特点是最后结束位一定是数字
74 int dot_flag = 0; //允许处理浮点数allow only one . like 3.332
75 int i2 = i;
76 while (i < len &&
77 (IsDigit(infix_string[i]) ||
78 (i < len -1 && infix_string[i]== '-' //-3被视为数字处理
79 && IsDigit(infix_string[i + 1])))) {
80 suffix_string += infix_string[i];
81 i++;
82 if (i < len && !dot_flag && infix_string[i] == '.') { //浮点数字处理
83 suffix_string += infix_string[i];
84 i++;
85 dot_flag = 1;
86 }
87 }
88
89 if (i > i2 && IsDigit(infix_string[i-1])) { // i>i2则表明刚处理了数字
90 suffix_string += ' ';
91 if (state != op) { //数字前面应该是运算符或者(
92 suffix_string.clear();
93 return false;
94 }
95 state = num;
96 } else if (i > i2 && dot_flag == 1) {
97 return false; //case like 3.
98 }
99
100
101 if (i == len) //we have done,(处理完最后一个数)
102 break;
103
104 //处理操作符,非数字情况
105 switch(infix_string[i]) {
106 case '(':
107 if (state != op) // (前面应该是运算符符或者(,左括号按照op处理
108 return false;
109 //state = op;
110 s.push('(');
111 break;
112 case ')':
113 if (state != num) // )前面应该是数字或者),右括号按照num处理
114 return false;
115 //state = num;
116 while(!s.empty() && s.top() != '(') { //如果能确保输入括号的正确性,则不需要!s.empty()的判断
117 suffix_string += s.top();
118 suffix_string += ' ';
119 s.pop();
120 }
121 if (s.empty()) //括号不匹配,缺左括号
122 return false;
123 s.pop(); // pop '('
124 break;
125 case '+': case '-': case '*': case '/':
126 if (state != num) //运算符前面应该是数字或者)
127 return false;
128 state = op;
129 while(!s.empty() && s.top() != '(' &&
130 (Priority(infix_string[i]) <= Priority(s.top()))) { //如果能确保输入括号的正确性,则不需要!s.empty()的判断
131 suffix_string += s.top();
132 suffix_string += ' ';
133 s.pop();
134 }
135 s.push(infix_string[i]);
136 break;
137 case ' ': case '\t': case '\r': //空格允许,但不处理, linux读的行是带\r的
138 break;
139 default: //遇到意外字符,输入有误
140 cout << "Unexpeced input, error, check your input" << endl;
141 return false;
142 }
143 }
144 if (state != num) //容易忽略,表达式尾部需要是数字
145 return false;
146 if (!s.empty()) //括号不匹配,左括号多,注意如果没有预处理的加最外面的括号,则需要继续pop出栈的
147 return false;
148 //去掉最后的空格
149 suffix_string.erase(string::size_type(suffix_string.size()-1), string::size_type(1));
150 //OK,finally convert sucessfully
151 return true;
152 }
153
154
155 inline bool IsNum(const string& s) {
156 return IsDigit(s[0]) || (s[0] == '-' && IsDigit(s[1]));
157 }
158
159 //后缀表达式求值,注意后缀表达式是用" "隔开的
160 double EvaluateSuffixString(const string &suffix_string) {
161 stringstream ss(suffix_string);
162 double elem, p, p1, p2;
163 string sub_str;
164 stack<double> s;
165 while(getline(ss,sub_str,' ')) {
166 //处理数字
167 if (IsNum(sub_str)) {
168 elem = ConvertString2Num<double>(sub_str);
169 s.push(elem);
170 } else { //运算符
171 p2 = s.top();
172 s.pop();
173 p1 = s.top();
174 s.pop();
175 switch(sub_str[0]) {
176 case '+':
177 p = p1 + p2;
178 break;
179 case '-':
180 p = p1 - p2;
181 break;
182 case '*':
183 p = p1 * p2;
184 break;
185 case '/':
186 p = p1 / p2;
187 break;
188 default:
189 cout << "error operator" << endl;
190 break;
191 }
192 s.push(p);
193 }
194 }
195 return s.top();
196 }
197
198 //判断给出的中缀表达式是否正确,括号匹配正确,无特殊字符,否则报错
199 //如果是正确的化转换成标准带空格的中缀表达式,如果有最外层括号,去掉
200 //(3+2) 视为正确的输入但是转换为3 + 2
201 //(3+2)*(4+6) 注意这样是没有最外层括号的
202 bool InfixStringNormallize(string &infix_string) {
203 //如果有最外层的括号,去掉它
204 int len = infix_string.length();
205 string infix_string2; //临时转换结果
206
207 stack<int> s;
208 int sum = 0; //标记是第几个(, 当如果末尾是)并且将0号(pop出来则有最外层括号
209 int pre_sum = -1; //标记当前是哪个标号的(出栈
210 State state = op; //开始第一个为数字或者左括号,期待前面是op
211 bool flag_bracket = false; //是否有最外层的括号:
212
213 for (int i = 0; i < len; i++) {
214 int dot_flag = 0; //允许处理浮点数allow only one . like 3.332
215 int i2 = i;
216 while (i < len &&
217 (IsDigit(infix_string[i]) ||
218 (i < len -1 && infix_string[i]== '-' //-3被视为数字处理
219 && IsDigit(infix_string[i + 1])))) {
220 infix_string2 += infix_string[i];
221 i++;
222 if (i < len && !dot_flag && infix_string[i] == '.') { //浮点数字处理
223 infix_string2 += infix_string[i];
224 i++;
225 dot_flag = 1;
226 }
227 }
228
229 if (i > i2 && IsDigit(infix_string[i-1])) { // i>i2则表明刚处理了数字
230 infix_string2 += ' ';
231 if (state != op) { //数字前面应该是运算符或者(
232 infix_string2.clear();
233 return false;
234 }
235 state = num;
236 } else if (i > i2 && dot_flag == 1) {
237 return false; //case like 3.
238 }
239
240
241 if (i == len) //we have done,(处理完最后一个数)
242 break;
243
244 //处理操作符,非数字情况
245 switch(infix_string[i]) {
246 case '(':
247 if (state != op) // (前面应该是运算符符或者(,左括号按照op处理
248 return false;
249 //state = op;
250 s.push(sum++);
251 infix_string2 += '(';
252 infix_string2 += ' ';
253 break;
254 case ')':
255 if (state != num) // )前面应该是数字或者),右括号按照num处理
256 return false;
257 //state = num;
258 if(s.empty()) //无左括号匹配
259 return false;
260 infix_string2 += ')';
261 infix_string2 += ' ';
262 pre_sum = s.top();
263 s.pop();
264 break;
265 case '+': case '-': case '*': case '/':
266 if (state != num) //运算符前面应该是数字或者)
267 return false;
268 state = op;
269 infix_string2 += infix_string[i];
270 infix_string2 += ' ';
271 break;
272 case ' ': case '\t': case '\r': //空格允许,但不处理, linux读的行是带\r的
273 break;
274 default: //遇到意外字符,输入有误
275 cout << "Unexpeced input, error, check your input" << endl;
276 return false;
277 }
278 }
279 if (state != num) //容易忽略,表达式尾部需要是数字
280 return false;
281 if (!s.empty()) //(未被匹配完
282 return false;
283 //注意infix_string2最后有一个多余的空格
284 int start = 0;
285 int end = infix_string2.size() - 2;
286 //最左边是(,最右边是),并且(是最后一个出栈的(,就是最外层有(),需要去除的情况
287 if (infix_string2[start] == '(' && infix_string2[end] == ')' && pre_sum == 0 )
288 flag_bracket = true;
289 if (flag_bracket) //去括号,注意空格
290 infix_string.assign(infix_string2.begin() + 2, infix_string2.end() - 3);
291 else //不需要去括号,但注意末尾的多余空格
292 infix_string.assign(infix_string2.begin(), infix_string2.end()- 1);
293 return true;
294 }
295
296 //中缀表达式直接求值,要求中缀表达式格式正确,且按空格隔开
297 //递归求解
298 //首先找根节点,根节点是括号外面的最后一个 +/-,或者*/ 如果括号外面没有+ -
299 //开始的时候处理成没有最外面括号的,但后面要再保证不出现
300 //忽略了括号问题,晕了,当出现例如(3+2)的时候,需要破括号
301 //唉,什么时候能够一遍写对呢? :) 思维不够缜密全面
302 //注意这种情况 (3+2)*(4+5) + 3 不能去成3+2)*(4+5
303 //所以从右向左扫描字符串
304 // TODO 当前函数只考虑了存在 + - 和 * /两种优先级的情况
305
306 //找根节点,本质上是找优先级最低的前提下最靠近右边的,如果有多个优先级,代码需要重写
307 //分裂可以修改函数改为只用下标标示分裂后的vec不需要真的assign,但可读性差
308 //或者改为list分裂 TODO 当前递归深度为d,就会用到d*(vec.size())的空间,每次向下都要新开vec.szie()的vec
309 //当前,可读最好,性能最差
310 //用下标递归,可读最差,性能最好
311 //用list 都居中
312
313
314 //注意这里用的end 指向最后一个元素
315 //而不是像vector end()指向末尾后面的元素
316 void SplitVec(const vector<string> &vec,
317 const int begin, const int end,
318 int &left_begin, int &left_end,
319 int &right_begin, int &right_end,
320 char &op) {
321 int pos = -1;
322 int candidate_pos = -1;
323 bool visited = false; //是否已经遇到过* /
324 stack<int> s; //s空表示在括号外部,每次入栈值+1
325 int sum = 0; //sum = 0表示入的是第一个括号,如果该括号最后才被出栈,则证明有最外()需要去除
326 int pre_sum = -1; //别忘了,因为*/ 是暂时人选,后面继续变化,但是如果最终选择,需要恢复其所有信息,包括最外括号信息
327 int pre_sum_candidate = -1;
328 char candidate_op;
329 bool left_flag = false; //是否有最外括号要去掉
330 bool right_flag = false;
331 //从右向左扫描数组
332 for (int i = end; i >= begin; i--) {
333 if (IsNum(vec[i]))
334 continue;
335 switch(vec[i][0]) {
336 case ')':
337 s.push(sum++);
338 break;
339 case '(':
340 pre_sum = s.top();
341 s.pop();
342 break;
343 case '+': case '-':
344 if (s.empty()) {
345 pos = i;
346 op = vec[i][0];
347 }
348 break;
349 case '*': case '/':
350 if (s.empty() && !visited) {
351 candidate_pos = i;
352 candidate_op = vec[i][0];
353 visited = true;
354 pre_sum_candidate = pre_sum;
355 }
356 break;
357 default:
358 cout << "error operator" << endl;
359 break;
360 }
361 if (pos != -1) //已经遇到括号外面的+ -了结束
362 break;
363 }
364
365 if (pos == -1) {
366 pos = candidate_pos;
367 op = candidate_op;
368 pre_sum = pre_sum_candidate;
369 }
370 if (vec[pos+1][0] == '(' && vec[end][0] == ')' && pre_sum == 0)
371 right_flag = true;
372 sum = 0;
373 pre_sum = -1;
374 //破括号!否则所有的符号都在括号内,无法继续了
375 if (vec[begin][0] == '(' && vec[pos-1][0] == ')') {
376 for (int i = begin; i < pos; i++) {
377 if (vec[i][0] == '(')
378 s.push(sum++);
379 if (vec[i][0] == ')') {
380 pre_sum = s.top();
381 s.pop();
382 }
383 }
384 if (pre_sum == 0)
385 left_flag = true;
386 }
387
388 // write the result
389 if (left_flag) {
390 left_begin = begin + 1;
391 left_end = pos - 2;
392 } else {
393 left_begin = begin;
394 left_end = pos - 1;
395 }
396
397 if (right_flag) {
398 right_begin = pos + 2;
399 right_end = end - 1;
400 } else {
401 right_begin = pos + 1;
402 right_end = end;
403 }
404
405 }
406 void SplitVec(const vector<string> &vec, vector<string> &vec_left,
407 vector<string> &vec_right, char &op) {
408 assert(vec.size() >= 3); //at least 3 + 2 using 3 space
409 int pos = -1;
410 int candidate_pos = -1;
411 bool visited = false; //是否已经遇到过* /
412 stack<int> s; //s空表示在括号外部,每次入栈值+1
413 int sum = 0; //sum = 0表示入的是第一个括号,如果该括号最后才被出栈,则证明有最外()需要去除
414 int pre_sum = -1; //别忘了,因为*/ 是暂时人选,后面继续变化,但是如果最终选择,需要恢复其所有信息,包括最外括号信息
415 int pre_sum_candidate = -1;
416 char candidate_op;
417 bool left_flag = false; //是否有最外括号要去掉
418 bool right_flag = false;
419 //从右向左扫描数组
420 for (int i = vec.size() - 1; i >= 0; i--) {
421 if (IsNum(vec[i]))
422 continue;
423 switch(vec[i][0]) {
424 case ')':
425 s.push(sum++);
426 break;
427 case '(':
428 pre_sum = s.top();
429 s.pop();
430 break;
431 case '+': case '-':
432 if (s.empty()) {
433 pos = i;
434 op = vec[i][0];
435 }
436 break;
437 case '*': case '/':
438 if (s.empty() && !visited) {
439 candidate_pos = i;
440 candidate_op = vec[i][0];
441 visited = true;
442 pre_sum_candidate = pre_sum;
443 }
444 break;
445 default:
446 cout << "error operator" << endl;
447 break;
448 }
449 if (pos != -1) //已经遇到括号外面的+ -了结束
450 break;
451 }
452
453 if (pos == -1) {
454 pos = candidate_pos;
455 op = candidate_op;
456 pre_sum = pre_sum_candidate;
457 }
458 if (vec[pos+1][0] == '(' && vec[vec.size()-1][0] == ')' && pre_sum == 0)
459 right_flag = true;
460 sum = 0;
461 pre_sum = -1;
462 //破括号!否则所有的符号都在括号内,无法继续了
463 if (vec[0][0] == '(' && vec[pos-1][0] == ')') {
464 for (int i = 0; i < pos; i++) {
465 if (vec[i][0] == '(')
466 s.push(sum++);
467 if (vec[i][0] == ')') {
468 pre_sum = s.top();
469 s.pop();
470 }
471 }
472 if (pre_sum == 0)
473 left_flag = true;
474 }
475 if (left_flag)
476 vec_left.assign(vec.begin() + 1, vec.begin() + pos - 1);
477 else
478 vec_left.assign(vec.begin(), vec.begin() + pos);
479 if (right_flag)
480 vec_right.assign(vec.begin() + pos + 2, vec.end() - 1);
481 else
482 vec_right.assign(vec.begin() + pos + 1, vec.end());
483 }
484
485 double EvaluateInfixStringHelp(const vector<string> &vec, int begin, int end) {
486 if (begin == end) {
487 return ConvertString2Num<double>(vec[begin]);
488 }
489
490 int left_begin, left_end, right_begin, right_end;
491 char op;
492
493 SplitVec(vec, begin, end,
494 left_begin, left_end,
495 right_begin, right_end, op);
496
497 switch(op) {
498 case '+':
499 return EvaluateInfixStringHelp(vec, left_begin, left_end) +
500 EvaluateInfixStringHelp(vec, right_begin, right_end);
501 break;
502 case '-':
503 return EvaluateInfixStringHelp(vec, left_begin, left_end) -
504 EvaluateInfixStringHelp(vec, right_begin, right_end);
505 break;
506 case '*':
507 return EvaluateInfixStringHelp(vec, left_begin, left_end) *
508 EvaluateInfixStringHelp(vec, right_begin, right_end);
509 break;
510 case '/':
511 return EvaluateInfixStringHelp(vec, left_begin, left_end) /
512 EvaluateInfixStringHelp(vec, right_begin, right_end);
513 break;
514 default:
515 break;
516 }
517
518 }
519 double EvaluateInfixStringHelp(const vector<string> &vec) {
520 //递归出口,只有一个数字
521 if (vec.size() == 1)
522 return ConvertString2Num<double>(vec[0]);
523
524 vector<string> vec_left, vec_right;
525 char op; //根的内容
526
527 SplitVec(vec, vec_left, vec_right, op);
528
529 switch(op) {
530 case '+':
531 return EvaluateInfixStringHelp(vec_left) +
532 EvaluateInfixStringHelp(vec_right);
533 break;
534 case '-':
535 return EvaluateInfixStringHelp(vec_left) -
536 EvaluateInfixStringHelp(vec_right);
537 break;
538 case '*':
539 return EvaluateInfixStringHelp(vec_left) *
540 EvaluateInfixStringHelp(vec_right);
541 break;
542 case '/':
543 return EvaluateInfixStringHelp(vec_left) /
544 EvaluateInfixStringHelp(vec_right);
545 break;
546 default:
547 break;
548 }
549 }
550
551 //要求执行之前infix_string 已经被normalize,
552 //空格间隔,没有最外层括号
553 double EvaluateInfixString(const string& infix_string) {
554 stringstream ss(infix_string);
555 string sub_str;
556 vector<string> vec;
557 // TODO how to improve below
558 while(getline(ss,sub_str,' '))
559 vec.push_back(sub_str);
560 // return EvaluateInfixStringHelp(vec);
561 return EvaluateInfixStringHelp(vec, 0, vec.size() - 1);
562 }
563
564 double EvaluateInfixString2(const string& infix_string) {
565 stringstream ss(infix_string);
566 string sub_str;
567 list<string> l;
568 while(getline(ss,sub_str,' '))
569 l.push_back(sub_str);
570 return EvaluateInfixStringHelp2(l);
571 }
572 double EvaluateInfixStringHelp2(list<string> &l) {
573 //递归出口,只有一个数字
574 if (l.size() == 1)
575 return ConvertString2Num<double>(*(l.begin()));
576
577 list<string> list_left, list_right;
578 char op; //根的内容
579
580 SplitList(l, list_left, list_right, op);
581
582 switch(op) {
583 case '+':
584 return EvaluateInfixStringHelp2(list_left) +
585 EvaluateInfixStringHelp2(list_right);
586 break;
587 case '-':
588 return EvaluateInfixStringHelp2(list_left) -
589 EvaluateInfixStringHelp2(list_right);
590 break;
591 case '*':
592 return EvaluateInfixStringHelp2(list_left) *
593 EvaluateInfixStringHelp2(list_right);
594 break;
595 case '/':
596 return EvaluateInfixStringHelp2(list_left) /
597 EvaluateInfixStringHelp2(list_right);
598 break;
599 default:
600 break;
601 }
602
603 }
604 void SplitList(list<string> &l, list<string> &list_left, list<string> &list_right, char &op) {
605 assert(l.size() >= 3); //at least 3 + 2 using 3 space
606 bool visited = false; //是否已经遇到过* /
607 stack<int> s; //s空表示在括号外部,每次入栈值+1
608 int sum = 0; //sum = 0表示入的是第一个括号,如果该括号最后才被出栈,则证明有最外()需要去除
609 int pre_sum = -1; //别忘了,因为*/ 是暂时人选,后面继续变化,但是如果最终选择,需要恢复其所有信息,包括最外括号信息
610 int pre_sum_candidate = -1;
611 char candidate_op;
612 bool left_flag = false; //是否有最外括号要去掉
613 bool right_flag = false;
614 //从右向左扫描数组
615 list<string>::iterator iter, pos_iter, candidate_pos_iter;
616 pos_iter = candidate_pos_iter = --l.begin();
617
618 for (iter = --l.end(); iter != --l.begin(); --iter) {
619 if (IsNum((*iter)))
620 continue;
621 switch((*iter)[0]) {
622 case ')':
623 s.push(sum++);
624 break;
625 case '(':
626 pre_sum = s.top();
627 s.pop();
628 break;
629 case '+': case '-':
630 if (s.empty()) {
631 pos_iter = iter;
632 op = (*iter)[0];
633 }
634 break;
635 case '*': case '/':
636 if (s.empty() && !visited) {
637 candidate_pos_iter = iter;
638 candidate_op = (*iter)[0];
639 visited = true;
640 pre_sum_candidate = pre_sum;
641 }
642 break;
643 default:
644 cout << "error operator" << endl;
645 break;
646 }
647 if (pos_iter != --l.begin()) //已经遇到括号外面的+ -了结束
648 break;
649 }
650
651 if (pos_iter == --l.begin()) {
652 pos_iter = candidate_pos_iter;
653 op = candidate_op;
654 pre_sum = pre_sum_candidate;
655 }
656
657 iter = pos_iter;
658 if (((*(++iter)))[0] == '(' && (*(--l.end()))[0] == ')' && pre_sum == 0)
659 right_flag = true;
660 sum = 0;
661 pre_sum = -1;
662 iter = pos_iter;
663 //破括号!否则所有的符号都在括号内,无法继续了
664 if ((*(l.begin()))[0] == '(' && (*(--iter))[0] == ')') {
665 for (iter = l.begin(); iter != pos_iter; iter++) {
666 if ((*iter)[0] == '(')
667 s.push(sum++);
668 if ((*iter)[0] == ')') {
669 pre_sum = s.top();
670 s.pop();
671 }
672 }
673 if (pre_sum == 0)
674 left_flag = true;
675 }
676
677 if (left_flag) {
678 iter = pos_iter;
679 --iter;
680 list_left.splice(list_left.end(), l, ++l.begin(), iter);
681 } else {
682 list_left.splice(list_left.end(), l, l.begin(), pos_iter);
683 }
684
685 iter = pos_iter;
686 if (right_flag) {
687 iter++;
688 iter++;
689 list_right.splice(list_right.end(), l, iter, --l.end());
690 } else {
691 iter++;
692 list_right.splice(list_right.end(), l, iter, l.end());
693 }
694 }
695
696 void CreateExpressionBinaryTree(const string& infix_string,
697 Tree &binary_tree) {
698 if (!binary_tree.IsEmpty())
699 binary_tree.DeleteBinaryTree(binary_tree.root());
700
701 //string内容按" "分开后存到vec中
702 stringstream ss(infix_string);
703 string sub_str;
704 vector<string> vec;
705 while(getline(ss,sub_str,' '))
706 vec.push_back(sub_str);
707 binary_tree.set_root(CreateExpressionBinaryTreeHelp(vec));
708 }
709
710 Node * CreateExpressionBinaryTreeHelp(
711 const vector<string> &vec) {
712 //递归出口,只有一个数字
713 if (vec.size() == 1)
714 return new Node(vec[0]);
715 vector<string> vec_left, vec_right;
716 char op;
717
718 SplitVec(vec, vec_left, vec_right, op);
719
720 //不能 string(char) 从类型‘char’到类型‘const char*’的转换无效
721 string op_string;
722 op_string += op;
723 Node * pnode = new Node(op_string);
724 pnode->set_left(CreateExpressionBinaryTreeHelp(vec_left));
725 pnode->set_right(CreateExpressionBinaryTreeHelp(vec_right));
726 return pnode;
727 }
728
729
730 } //end of namespace expression