中缀表达式是我们熟悉的表达式形式。为了能正确表示运算的先后顺序,中缀表达式中难免要出现括号。假设我们的表达式中只允许有圆括号。 读入一个浮点数为操作数的中缀表达式后,对该表达式进行运算。 要求中缀表达式以一个字符串的形式读入,可含有加、减、乘、除运算符和左、右括号,并假设该表达式以“#”作为输入结束符。 如输入“3.5*(20+4)-1#”,则程序运行结果应为83。 要求可单步显示输入序列和栈的变化过程。并考虑算法的健壮性,当表达式错误时,要给出错误原因的提示。 附:大家可扩展考虑后缀表达式求值、中缀表达式求值、括号匹配等栈的综合应用
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<stack> 5 #include<sstream> 6 #include<map> 7 using namespace std; 8 void str_to_double(vector<double>&d, string s); 9 void remove_num(string &s); 10 void init_map(map<char, int> &m); 11 void process_data(vector<double> &num, stack<double> & stack_of_num, stack<char> & stack_of_punction, string copy1, string copy2, map<char, int> priority); 12 int check_vaild(string &s); 13 14 int main() { 15 vector<double> num; //记录输入string中所有的double 16 17 string infix_expression; 18 while (true) { 19 cout << "请输入您的中缀表达式: " << endl; 20 cin >> infix_expression; 21 22 if (check_vaild(infix_expression) == 1) 23 cout << "输入没有以#结尾,请从新输入." << endl; 24 else if (check_vaild(infix_expression) == 2) 25 cout << "输入表达式括号不匹配,请重新输入." << endl; 26 else if (check_vaild(infix_expression) == 3) 27 cout << "输入表达式含有其他不合法字符,请重新输入." << endl; 28 else if (check_vaild(infix_expression) == 4) 29 cout << "输入表达式不合逻辑,请检查后重新输入." << endl; 30 else 31 break; //保证用户输入数据一定合法,不合法会重新输入,不会直接终止程序; 32 } 33 34 string copy1 = infix_expression; 35 str_to_double(num, copy1); 36 37 string copy2 = infix_expression; 38 remove_num(copy2); 39 40 stack<double> stack_of_num; 41 stack<char> stack_of_punction; 42 43 map<char, int> priority; 44 init_map(priority); 45 46 process_data(num, stack_of_num, stack_of_punction, copy1, copy2, priority); 47 //cout << copy2 << endl; 48 cout << infix_expression << "=" << stack_of_num.top() << endl; 49 return 0; 50 } 51 52 53 void str_to_double(vector<double>&d, string s) { 54 /* 55 函数首先将string转化为只含数字和小数点的string 56 然后利用字符串流,读出所有的double,push_back到容器中去 57 */ 58 for (size_t i = 0; i < s.size(); i++) { 59 if (!((s[i] >= '0' && s[i] <= '9') || (s[i] == '.'))) 60 s[i] = ' '; 61 } 62 istringstream iss(s); //string流 63 double num; 64 while (iss >> num) { 65 d.push_back(num); 66 } 67 } 68 69 void remove_num(string &s) { 70 /* 71 函数将string中的数字剔除string,且将原来的数字用空格代替,需要注意,一个浮点数如3.5只能用一个空格代替,这样方便接下来的处理。 72 */ 73 string res = ""; 74 char pre = '?'; //记录上次操作是否为右括号 75 for (size_t i = 0; i < s.length(); i++) { 76 if ((s[i] >= '0' && s[i] <= '9') || (s[i] == '.')) 77 continue; 78 else { 79 if (s[i] == '(') 80 res += s[i]; 81 else if (s[i] == ')' && pre != ')') 82 res = res + " " + s[i]; 83 else if (s[i] == ')' && pre == ')') 84 res += s[i]; 85 else if (pre != ')') 86 res = res + " " + s[i]; 87 else if (pre == ')') 88 res += s[i]; 89 } 90 pre = s[i]; 91 } 92 s = res; 93 } 94 //例如: 95 //3.5*(20+4)-1# 用户输入 96 //3.5 20 4 -1 所有操作数的容器 97 // *( + )- # 去除数字后的string 98 // *( + )- # 最多只含一个空格的string 99 100 //设置两个栈 101 //数字栈 3.5 20 4 102 //符号栈 * ( + ) 103 //如果string[i]是空格 数字栈push 104 //如果符号 当不是括号 判断栈空? 105 //不空 如果栈中符号优先级大 top 且 pop (取一个操作符 数字栈弹出两个 push一个结果) 否则 压栈 106 107 //如果左括号 压栈(进栈后优先级要变,这样避免在没有出现右括号时左括号由于优先级较大被弹出) 之后如果没读到右括号 继续上述操作符操作 108 //右括号 直到遇到左括号 要不然继续上述操作符操作 109 110 void process_data(vector<double> &num, stack<double> & stack_of_num, stack<char> & stack_of_punction, string copy1, string copy2, map<char, int> priority) { 111 /* 112 函数功能见上面几行文字 113 */ 114 int pos_of_num = 0; //记录数字栈取到了第几个数 115 char tmp; //记录零时操作符 116 double x1, x2; //记录零时操作数 117 for (size_t i = 0; i < copy2.size(); i++) { 118 if (copy2[i] == ' ') { //读到数字 119 cout << "数字栈push了" << num[pos_of_num] << endl; 120 stack_of_num.push(num[pos_of_num++]); //压数字栈,pos++ 121 } 122 else { 123 if (copy2[i] != '(' && copy2[i] != ')') { 124 while (!stack_of_punction.empty() && (priority[stack_of_punction.top()] >= priority[copy2[i]])) { 125 //优先级比较 看 栈顶元素优先级和即将push的谁的优先级大 126 char x = stack_of_punction.top(); 127 stack_of_punction.pop(); 128 cout << "符号栈pop了" << x << endl; 129 x1 = stack_of_num.top(); 130 stack_of_num.pop(); 131 cout << "数字栈pop了" << x1 << endl; 132 x2 = stack_of_num.top(); 133 stack_of_num.pop(); 134 cout << "数字栈pop了" << x2 << endl; 135 switch (x) 136 { 137 case '+': 138 stack_of_num.push(x1 + x2); 139 cout << x2 << "+" << x1 << "=" << x1 + x2 << endl; 140 cout << "数字栈push了" << x1 + x2 << endl; 141 break; 142 case '-': 143 stack_of_num.push(x2 - x1); 144 cout << x2 << "-" << x1 << "=" << x2 - x1 << endl; 145 cout << "数字栈push了" << x2 - x1 << endl; 146 break; 147 case '*': 148 stack_of_num.push(x1 * x2); 149 cout << x2 << "*" << x1 << "=" << x1 * x2 << endl; 150 cout << "数字栈push了" << x1*x2 << endl; 151 break; 152 case'/': 153 stack_of_num.push(x2 / x1); 154 cout << x2 << "/" << x1 << "=" << x2 / x1 << endl; 155 cout << "数字栈push了" << x2 / x1 << endl; 156 break; 157 default: 158 break; 159 } 160 } 161 if (stack_of_punction.empty() || (priority[stack_of_punction.top()] < priority[copy2[i]])) { 162 //如果栈空 或者 栈顶元素优先级小 把即将要push的元素push 163 stack_of_punction.push(copy2[i]); 164 cout << "符号栈push了" << copy2[i] << endl; 165 } 166 } 167 else if (copy2[i] == '(') { 168 stack_of_punction.push('['); //改变左括号优先级 169 cout << "符号栈push了(" << endl; 170 } 171 else if (copy2[i] == ')') { 172 while (stack_of_punction.top() != '[') { //遇到右括号但是没有遇到左括号 173 tmp = stack_of_punction.top(); 174 stack_of_punction.pop(); 175 cout << "符号栈pop了" << tmp << endl; 176 x1 = stack_of_num.top(); 177 stack_of_num.pop(); 178 cout << "数字栈pop了" << x1 << endl; 179 x2 = stack_of_num.top(); 180 stack_of_num.pop(); 181 cout << "数字栈pop了" << x2 << endl; 182 switch (tmp) 183 { 184 case '+': 185 stack_of_num.push(x1 + x2); 186 cout << x2 << "+" << x1 << "=" << x1 + x2 << endl; 187 cout << "数字栈push了" << x1 + x2 << endl; 188 break; 189 case '-': 190 stack_of_num.push(x2 - x1); 191 cout << x2 << "-" << x1 << "=" << x2 - x1 << endl; 192 cout << "数字栈push了" << x2 - x1 << endl; 193 break; 194 case '*': 195 stack_of_num.push(x1 * x2); 196 cout << x2 << "*" << x1 << "=" << x1 * x2 << endl; 197 cout << "数字栈push了" << x1*x2 << endl; 198 break; 199 case '/': 200 stack_of_num.push(x2 / x1); 201 cout << x2 << "/" << x1 << "=" << x2 / x1 << endl; 202 cout << "数字栈push了" << x2 / x1 << endl; 203 break; 204 //default: 205 // break; 206 } 207 } 208 if (stack_of_punction.top() == '[') //遇到了左括号,弹出栈 209 stack_of_punction.pop(); 210 } 211 } 212 } 213 } 214 215 216 void init_map(map<char, int> &m) { 217 char a[] = { '#', '[', ']', '+', '-', '*', '/', '(', ')' }; 218 int b[] = { -1 , 0 , 0 , 1 , 1 , 2 , 2 , 3 , 3 }; 219 for (size_t i = 0; i < 9; i++) { 220 m.insert(pair<char, int>(a[i], b[i])); 221 } 222 } 223 //左右括号入栈后优先级降为最低,保证在没有读到右括号时,左括号不被弹出. 224 //左右括号在入栈前与top比较时,使左右括号优先级最高,保证读入括号时栈中元素不弹出; 225 226 int check_vaild(string &s) { 227 /* 228 函数判断输入的string是否合法,包括检查末尾是否为# 229 */ 230 string tmp = s; 231 remove_num(tmp); 232 //检查末尾是否为# 233 if (tmp[tmp.size() - 1] != '#') 234 return 1; 235 //检查括号是否匹配 236 stack<char> bracket; 237 for (int i = 0; i < tmp.length(); i++) { 238 if (tmp[i] == '(') 239 bracket.push('('); 240 else if (tmp[i] == ')') { 241 if (bracket.empty()) 242 return 2; 243 else 244 bracket.pop(); 245 } 246 } 247 248 //检查是否含其他字符 249 for (size_t i = 0; i < tmp.length(); i++) { 250 if (tmp[i] != '+' && tmp[i] != '-' && tmp[i] != '*' && tmp[i] != '/' && tmp[i] != '(' && tmp[i] != ')' && tmp[i] != '#' && tmp[i]!=' ') 251 return 3; 252 } 253 //检查表达式是否符合逻辑 254 //可以看到 当合法的表达式去除所有()和#时 一定是数字 运算符 数字 运算符 这样成对出现的 且以数字结尾 255 int sum = 0; 256 for (size_t i = 0; i<tmp.length(); i++) { 257 if (tmp[i] == ' ') 258 sum++; 259 else if (tmp[i] == '+' || tmp[i] == '-' || tmp[i] == '*' || tmp[i] == '/') 260 sum--; 261 if (sum != 0 && sum != 1) 262 return 4; 263 } 264 if (sum == 0) //最后没有一个是符号,匹配错误; 265 return 4; 266 267 return 0; 268 }