题目链接:https://pintia.cn/problem-sets/15/problems/827
参考:https://blog.csdn.net/SiKongPop/article/details/77972879#comments(内附数个测试样例)
题意:
将输入中缀表达式转换为后缀表达式,输入字符包含'+' '-' '*' '/' '(' ')'。输出的每个操作数或操作符用空格间隔开,并且末尾不能输出多余空格。
特别注意:操作数是可以有多位的,并且可以是小数,也就是说会包含有小数点,同时有的操作数是带符号的,带+号的不用输出+号,但是带-号的需要输出-号。
如果不把这些考虑进去注意,会有格式错误。
中缀到后缀的代码逻辑:
先准备一个栈S用来存储操作符,然后对输入的表达式的每个字符逐个处理。
对于输入的字符进行如下判断:
1)如果是'(',直接压入栈S。
2)如果是'*' '/' '+' '-',将S的栈顶出栈与输入的字符进行对比,如果输入操作符优先级小于等于栈顶操作符,则先输出栈顶操作符,再将输入的操作符压入栈S。
3)如果是')',S出栈,判断出栈的字符是不是'(',如果不是,则输出,否则,直接退出判断。
处理多位数,小数以及带符号数的方法:
1)首先要清楚什么地方会出现带符号的数,第一种情况是在输出结果的开头,比如“-2+1”,第二种情况是在括号里面,即紧接着'(',例如“(-2+1)”或者“(-2)+1”。
2)如果(1)的条件满足,则顺着下去判断,逐个判断接下来输入的字符,如果仍然是数字或者小数点,就接着输出,如果遇到了非数字和非小数点的字符,就结束输出(此时一个操作数的输出已经完成,可以进行下一个输入的操作符的判断。)
3)如果只是不带符号的数,那么也跟(2)一样,从第一个数字开始逐个判断下一个数,与(2)同理。
结果是如何输出的:
1)对于操作数,读入之后按要求处理后直接输出即可。
2)对于操作符,一部分是在操作符入栈时优先级比栈顶操作符低级(或与栈顶操作符平级)的时候将栈顶操作符输出,剩下一部分是在程序最后面,将剩下未出栈的操作符逐个出栈输出。
AC代码:
1 #include <iostream> 2 #include <string> 3 #include <cstring> 4 using namespace std; 5 6 class stack_//定义栈 7 { 8 public: 9 stack_() :r(-1) {} 10 ~stack_() {} 11 void push(char k) 12 { 13 s[++r] = k; 14 } 15 char pop() 16 { 17 if (r != -1) 18 return s[r--]; 19 else 20 return '\0';//如果栈为空,就返回'\0' 21 } 22 public: 23 char s[1000]; 24 int r; 25 }; 26 27 int main() 28 { 29 stack_ operate_;//用来存放操作符 30 char exp_[1000];//用来接收输入的表达式 31 int cnt = 0;//计数,若为0说明是所输出结果的第一个字符,每次输出之后自增 32 33 cin.getline(exp_, 1000);//输入表达式 34 for (int i = 0; i < 1000; i++)//遍历所输入表达式的每一个字符 35 { 36 if ('\0' == exp_[i])break;//遍历完成,退出循环 37 //判断:+-号是不是在'('后一个,或者在开头。这是出现带符号数字的惟二条件: 38 //即出现在开头或以类似(-2+3)的形式出现,这里对是不是符合两个条件进行判断 39 if ( 40 (i == 0 && (exp_[i] == '-' || exp_[i] == '+')) || 41 (i >= 1 && ((exp_[i] == '-' || exp_[i] == '+') && exp_[i - 1] == '(')) 42 )//判断条件是否满足 43 { 44 if (exp_[i] == '-')//如果是符号是'-' 45 { 46 if (cnt == 0) 47 { 48 cout << '-'; cnt++;//为输出的第一个字符,不需要输出空格,直接输出'-',cnt自增 49 } 50 else 51 { 52 cout << ' ' << '-'; //若非第一个字符,则在前面先输出一个空格,因为cnt已不为0,不自增也可以 53 } 54 } 55 else if (exp_[i] == '+')//类似上面 56 { 57 if (cnt == 0)cnt++;//注意此处,虽然并没有输出,但也要自加,否则输出完下面数字后的再下一次输出,会被误认为是第一次输出 58 else 59 { 60 cout << ' '; //如果不是第一个,就只输出空格,因为+号是不用输出的 61 } 62 } 63 64 int j; 65 for (j = i + 1;; j++) 66 { 67 if ((exp_[j] >= '0' && exp_[j] <= '9') || exp_[j] == '.') 68 { 69 cout << exp_[j];//cnt不用自增,因为上面输出符号的时候已经处理过cnt了, 70 //此处输出数字的时候可以不考虑是第一次输出的情况 71 } 72 else break;//如果遇到的字符不是数字或者小数点,就可以结束此次输出 73 } 74 j--;//此时数组j下标放的是继上一次输出数字后的第一个非数字或小数点字符 75 //下次循环理应从这里开始判断,但是因为进入下一次循环i要++,所以这里先--一次 76 //抵消掉一次++,再赋给i 77 i = j; 78 continue;//下一次循环,开始下一个字符的判断 79 } 80 //判断输入字符是不是数字,此处 81 else if (exp_[i] >= '0' && exp_[i] <= '9') 82 {//逻辑与上面一个if类似 83 if (cnt == 0) 84 { 85 cout << exp_[i]; cnt++; 86 } 87 else 88 { 89 cout << ' ' << exp_[i]; 90 } 91 int j; 92 for (j = i + 1;; j++) 93 { 94 if ((exp_[j] >= '0' && exp_[j] <= '9') || exp_[j] == '.') 95 { 96 cout << exp_[j]; 97 } 98 else break; 99 } 100 j--; 101 i = j; 102 continue; 103 } 104 //判断输入字符是不是'(' 105 else if (exp_[i] == '(') 106 { 107 operate_.push(exp_[i]);//如果是,可以直接压入栈 108 continue;//下一次循环,继续判断下一个输入的字符 109 } 110 //判断是不是输入'*'或'/',注意''里面只能含有操作符, 111 //不能带空格,否则判断的时候会出现错误 112 else if (exp_[i] == '*' || exp_[i] == '/') 113 { 114 while (1) 115 { 116 char ch = operate_.pop(); 117 if (ch != '\0')//如果不是空栈 118 { 119 if (ch != '/' && ch != '*')//如果不是'/'或'*',说明栈顶操作符是优先级更低的,直接压入栈即可 120 { 121 operate_.push(ch);//先将刚刚出栈的栈顶元素重新压回栈 122 operate_.push(exp_[i]);//再将操作符'*'或'/'压入 123 break; 124 } 125 else//若遇到优先级相同的,先输出旧的,再压入新的 126 { 127 if (cnt == 0) 128 { 129 cout << ch; cnt++; 130 } 131 else 132 cout << ' ' << ch; 133 continue; 134 } 135 } 136 else//空栈 137 { 138 operate_.push(exp_[i]); 139 break; 140 } 141 } 142 } 143 //判断'+'或'-' 144 else if (exp_[i] == '+' || exp_[i] == '-')//逻辑同上 145 { 146 while (1) 147 { 148 char ch = operate_.pop(); 149 if (ch != '\0') 150 { 151 if (ch != '/' && ch != '*' && ch != '+' && ch != '-') 152 { 153 operate_.push(ch); 154 operate_.push(exp_[i]); 155 break; 156 } 157 else 158 { 159 if (cnt == 0) 160 { 161 cout << ch; cnt++; 162 } 163 else 164 cout << ' ' << ch; 165 continue; 166 } 167 } 168 else 169 { 170 operate_.push(exp_[i]); 171 break; 172 } 173 } 174 } 175 //判断')' 176 else if (exp_[i] == ')') 177 { 178 char ch; 179 while (1) 180 { 181 ch = operate_.pop(); 182 if (ch != '\0')//如果不为空栈 183 { 184 if (ch != '(')//若没有遇到'(',直接输出出栈的元素 185 { 186 if (cnt == 0) 187 { 188 cout << ch; cnt++; 189 } 190 else 191 cout << ' ' << ch; 192 continue; 193 } 194 else 195 { 196 break;//如果所出栈的字符是'(',则停止出栈 197 } 198 } 199 else//如果是空栈,直接退出 200 { 201 break; 202 } 203 } 204 } 205 }//big for 206 //此处将没有出栈的操作符全部出栈 207 while (operate_.r != -1) 208 { 209 char ch = operate_.pop(); 210 if (cnt == 0) 211 { 212 cout << ch; cnt++; 213 } 214 else 215 cout << ' ' << ch; 216 } 217 return 0; 218 }