用栈实现计算器

中缀表达式是我们熟悉的表达式形式。为了能正确表示运算的先后顺序,中缀表达式中难免要出现括号。假设我们的表达式中只允许有圆括号。
读入一个浮点数为操作数的中缀表达式后,对该表达式进行运算。
要求中缀表达式以一个字符串的形式读入,可含有加、减、乘、除运算符和左、右括号,并假设该表达式以“#”作为输入结束符。
如输入“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 }

 

转载于:https://www.cnblogs.com/Jovesun/p/11578466.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值