知识点与难度
字符串、基础数学、栈、中等难度
描述
输入一个表达式(用字符串表示),求这个表达式的值。
保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。
数据范围:表达式计算结果和过程中满足 ∣val∣≤1000 ,字符串长度满足 1≤n≤1000
输入描述:
输入一个算术表达式
输出描述:
得到计算结果
输入输出示例:
输入:
3+2*{1+2*[-4/(8-6)+7]}
输出:
25
我的代码:
#include <iostream>
#include <stack>
using namespace std;
int checkNumber(char c) {
if ('0' <= c && c <= '9') {
return c - '0';
}
return -1;
}
int getPriority(char c) {
if (c == '+' || c == '-') {
return 0;
} else if (c == '*' || c == '/') {
return 1;
} else if (c == '#' || c == '(' || c == '{' || c == '[') {
return -1;
} else {
return 2;
}
}
float getCalculation(char opt, float n1, float n2) {
//cout << n1 << opt << n2 << endl;
if (opt == '+') {
return n1 + n2;
} else if (opt == '-') {
return n1 - n2;
} else if (opt == '*') {
return n1 * n2;
} else {
return n1 / n2;
}
}
int main() {
string s;
int start = 1;
int minus = 0;
stack<float> num;
stack<char> op;
op.emplace('#');
float temp;
int n;
int priority;
float n1; //数一
float n2; //数二
char opt; //运算符
int key = 0;
while (cin >> s) { // 注意 while 处理多个 case
int i = 0;
while (i < s.length()) {
// 负数的特殊处理
if (start == 1) {
if (s[i] == '-') {
minus = 1;
i++;
}
start = 0;
}
//读取数字
temp = 0;
while (i < s.length() && (n = checkNumber(s[i])) != -1) {
temp = temp * 10 + n;
key = 1;
i++;
}
if (key != 0) {
if (minus == 1) {
num.emplace(-temp);
minus = 0;
} else {
num.emplace(temp);
}
key = 0;
}
//读取操作符
while (i < s.length() && (n = checkNumber(s[i])) == -1) {
if (start == 1) {
if (s[i] == '-') {
minus = 1;
i++;
}
start = 0;
continue;
}
priority = getPriority(s[i]);
if (priority == 2) { //右括号
while (getPriority(op.top()) != -1) {
opt = op.top();
op.pop();
n2 = num.top();
num.pop();
n1 = num.top();
num.pop();
n1 = getCalculation(opt, n1, n2);
num.emplace(n1);
}
op.pop();
} else if (priority == -1) { //左括号
op.emplace(s[i]);
start = 1;
} else { //运算符
while (priority <= getPriority(op.top()) ) {
opt = op.top();
op.pop();
n2 = num.top();
num.pop();
n1 = num.top();
num.pop();
n1 = getCalculation(opt, n1, n2);
num.emplace(n1);
}
op.emplace(s[i]);
}
i++;
}
}
while (num.size() > 1) {
opt = op.top();
op.pop();
n2 = num.top();
num.pop();
n1 = num.top();
num.pop();
n1 = getCalculation(opt, n1, n2);
num.emplace(n1);
}
cout << num.top() << endl;
}
}
// 64 位输出请用 printf("%lld")
我的代码分析:
首先定义符号栈与数字栈,当输入数字时入数字栈,当输入符号时,查看当前符号与符号栈顶元素的优先级,若优先级当前符号大于栈顶符号,则入栈,否则,符号栈弹出一个运算符,数字栈弹出两个数字,运算后的结果压入数字栈。特殊的,输入左括号时直接入栈,输入右括号时出栈运算直到左括号出栈。当输入完成时,进行出栈运算,直到栈底只剩一个元素,该元素即为计算结果。
checkNumber() 用来检验是否为数字,是数字返回数字0-9,不是返回-1。
getPriority() 用来获取运算符优先级,加减为0,乘除为1,所有左括号与#号为-1,右括号为2。
getCalculation() 进行二元运算返回结果。
因为在表达式与括号内的头部可能出现负数,因此要校验一下开头是不是负数,用start变量标识是否为表达式或括号的开头,用minus变量标识开头是否为负数。之后循环读取数字,压入数字栈。接下来读取操作符,根据输入进行运算。表达式读取完成,出栈运算,直到只剩下一个元素。
top1代码:
#include <iostream>
#include <string.h>
using namespace std;
int char_i = 0;//使用全局变量,防止递归产生的无线循环
int cal(char *character){
int result = 0;
int num[100] = {0};
int num_index = 0;
char sigh = '+';
int len = strlen(character);
while(char_i<len){
int num_m = 0;
if(character[char_i]=='('||character[char_i]=='['||character[char_i]=='{'){
char_i++;
num_m = cal(character);
}
while (1)
{
if (character[char_i] >= '0' && character[char_i] <= '9')
{
num_m = num_m * 10 + character[char_i] - '0';
char_i++;
}
else
break;
}
switch(sigh){
case '+':
num[num_index] = num_m;
num_index++;
break;
case '-':
num[num_index] = -num_m;
num_index++;
break;
case '*':
num[num_index-1] *= num_m;
break;
case '/':
num[num_index-1] /= num_m;
break;
default:
break;
}
sigh = character[char_i];
if (character[char_i] == '}' || character[char_i] == ']' || character[char_i] == ')') {//结束本次递归,返回括号内运算的结果
char_i++;
break;
}
char_i++;
}
for (int i = 0; i < num_index; i++)
{
result += num[i];
}
return result;
}
int main() {
char character[100] = { 0 };
int result = 0;
cin >> character;
result = cal(character);
cout << result << endl;
}
top1代码分析:
只使用一个数字数组,将整个表达式转换成一个加法运算。预设一个‘+’运算符,这样当第一个数字为负数时,补了一个+0,之后的加法运算就是向数字数组中添加一个正数,减法运算添加一个负数,乘除法则是取前一个数字进行运算后返回数组。对于括号则是进行递归调用,计算完括号中的内容后返回。
总结:
将整个表达式转换成一个加法运算,我觉得还挺妙的,对于括号这种形式的运算,也要想到递归的算法来简化问题。