今天遇到了一个问题,来用GPT解决一下。
问题:
求一个可能包含加、减、乘、除、乘方运算的中缀表达式的值。
在计算机中,我们常用栈来解决这一问题。首先将中缀表达式转换到后缀表达式,然后对后缀表达式求值。
加、减、乘、除、乘方分别用+,-,*, /, ^来表示。表达式可以有圆括号()。
输入第一行为测试数据的组数N。 接下来的N行,每行是一个中缀表达式。 每个表达式中,圆括号、运算符和运算数相互之间都用空格分隔,运算数是整数。一般运算数可正可负(负数的符号和数字之间无空格),指数一定为自然数(0和正整数)。不必考虑除0的情况。每个运算数均可由int放下。不必考虑溢出。中缀表达式的字符串长度不超过600。乘方的优先级比乘除都高,结合性是向左结合,如2 ^ 3 ^ 4表示( 2 ^ 3 ) ^ 4 = 4096。除法的商向下取整。
输出对每一组测试数据输出一行,为表达式的值
样例输入2
31 * ( 5 - ( -3 + 25 ) ) + 70 ^ 2
2 * 5 + 6 * ( 7 - 8 ) + 6
样例输出4373
10
基本程序的得出
我把题目概括了一下:c++ 输入一个中缀表达式,求值。
一.
GPT回答道:
要在C++中求解中缀表达式的值,需要使用表达式求值的算法。以下是一种基于栈的算法来实现:
创建两个栈,一个用于存储操作数(Operand Stack),一个用于存储运算符(Operator Stack)。
从左到右遍历中缀表达式的每个字符。
如果当前字符是数字,将其添加到操作数栈中。
如果当前字符是运算符,检查运算符栈的栈顶元素(如果有)。如果运算符栈为空,或者栈顶元素是左括号"(",则直接将当前运算符入栈。
如果当前运算符的优先级大于栈顶运算符的优先级,则将其入栈。
如果当前运算符的优先级小于或等于栈顶运算符的优先级,则从运算符栈弹出栈顶元素,并从操作数栈中弹出两个操作数。使用弹出的运算符对两个操作数进行计算,并将结果压入操作数栈。重复此过程,直到满足上述条件。
如果当前字符是左括号"(",将其入栈。
如果当前字符是右括号")",则从运算符栈中连续弹出运算符,并从操作数栈中连续弹出两个操作数进行计算,直到遇到左括号为止。将左括号弹出丢弃。
重复步骤2到步骤8,直到遍历完整个中缀表达式。
当表达式遍历完毕后,运算符栈和操作数栈中可能还存在元素。按照步骤6和步骤8进行计算和处理,直到运算符栈为空。
最终,操作数栈中的唯一元素就是中缀表达式的求值结果。
下面是一个简单的C++示例代码来实现上述算法:
#include <iostream> #include <stack> #include <string> using namespace std; int precedence(char op) { if (op == '+' || op == '-') return 1; if (op == '*' || op == '/') return 2; return 0; } int applyOperator(int a, int b, char op) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } return 0; } int evaluateExpression(string expression) { stack<int> operandStack; stack<char> operatorStack; for (char& c : expression) { if (c == ' ') continue; if (isdigit(c)) { operandStack.push(c - '0'); } else if (c == '(') { operatorStack.push(c); } else if (c == ')') { while (!operatorStack.empty() && operatorStack.top() != '(') { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = applyOperator(a, b, op); operandStack.push(result); } if (!operatorStack.empty() && operatorStack.top() == '(') { operatorStack.pop(); } } else { while (!operatorStack.empty() && precedence(c) <= precedence(operatorStack.top())) { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = applyOperator(a, b, op); operandStack.push(result); } operatorStack.push(c); } } while (!operatorStack.empty()) { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = applyOperator(a, b, op); operandStack.push(result); } return operandStack.top(); } int main() { string expression; cout << "请输入中缀表达式:"; getline(cin, expression); int result = evaluateExpression(expression); cout << "表达式的值为:" << result << endl; return 0; }
你可以运行上述代码,并输入一个中缀表达式,程序将输出该表达式的求值结果。例如,输入表达式"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3",输出结果为1。请注意,中缀表达式中的运算符之间必须用空格隔开。
二.
但显然,少了乘方的运算,所以我说:加入乘方的运算。
GPT:
要加入乘方运算的支持,可以在表达式求值的算法中进行修改。以下是修改后的C++示例代码:
#include <iostream> #include <stack> #include <string> #include <cmath> using namespace std; int precedence(char op) { if (op == '+' || op == '-') return 1; if (op == '*' || op == '/') return 2; if (op == '^') return 3; return 0; } int applyOperator(int a, int b, char op) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; case '^': return pow(a, b); } return 0; } int evaluateExpression(string expression) { stack<int> operandStack; stack<char> operatorStack; for (char& c : expression) { if (c == ' ') continue; if (isdigit(c)) { operandStack.push(c - '0'); } else if (c == '(') { operatorStack.push(c); } else if (c == ')') { while (!operatorStack.empty() && operatorStack.top() != '(') { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = applyOperator(a, b, op); operandStack.push(result); } if (!operatorStack.empty() && operatorStack.top() == '(') { operatorStack.pop(); } } else { while (!operatorStack.empty() && precedence(c) <= precedence(operatorStack.top())) { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = applyOperator(a, b, op); operandStack.push(result); } operatorStack.push(c); } } while (!operatorStack.empty()) { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = applyOperator(a, b, op); operandStack.push(result); } return operandStack.top(); } int main() { string expression; cout << "请输入中缀表达式:"; getline(cin, expression); int result = evaluateExpression(expression); cout << "表达式的值为:" << result << endl; return 0; }
在这个修改后的代码中,主要进行了以下几个方面的修改:
在
precedence
函数中增加了乘方运算符'^'
的优先级,将其设置为最高优先级(如3)。在
applyOperator
函数中,增加了对乘方运算的处理。使用pow
函数来计算a
的b
次幂的结果。在
evaluateExpression
函数中,对解析表达式的逻辑进行了修改。当遇到一个运算符时,需要先判断其优先级是否小于或等于栈顶运算符的优先级,如果是,则需要将栈中较高优先级的运算符依次弹出,并进行计算。因此,在while
循环中,增加了对运算符优先级的判断。在
main
函数中,获取用户输入的表达式时,需要保证运算符之间有空格分隔。这些修改使得代码能够正确处理乘方运算符,可以计算包含乘方运算的中缀表达式的值。
三.
还少了一个功能,即输入多组数据的,所以我说:增加循环,使程序可以输入N个数
GPT回答道:
以下是修改后的代码实现了循环输入N个表达式,并输出它们的计算结果:
#include <iostream> #include <stack> #include <string> #include <cmath> using namespace std; int precedence(char op) { if (op == '+' || op == '-') return 1; if (op == '*' || op == '/') return 2; if (op == '^') return 3; return 0; } int applyOperator(int a, int b, char op) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; case '^': return pow(a, b); } return 0; } int evaluateExpression(string expression) { stack<int> operandStack; stack<char> operatorStack; for (char& c : expression) { if (c == ' ') continue; if (isdigit(c)) { operandStack.push(c - '0'); } else if (c == '(') { operatorStack.push(c); } else if (c == ')') { while (!operatorStack.empty() && operatorStack.top() != '(') { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = applyOperator(a, b, op); operandStack.push(result); } if (!operatorStack.empty() && operatorStack.top() == '(') { operatorStack.pop(); } } else { while (!operatorStack.empty() && precedence(c) <= precedence(operatorStack.top())) { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = applyOperator(a, b, op); operandStack.push(result); } operatorStack.push(c); } } while (!operatorStack.empty()) { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = applyOperator(a, b, op); operandStack.push(result); } return operandStack.top(); } int main() { int n; cout << "请输入表达式的个数:"; while (cin >> n) { cin.get(); // 读取掉回车符 for (int i = 1; i <= n; i++) { string expression; cout << "请输入第" << i << "个中缀表达式:"; getline(cin, expression); int result = evaluateExpression(expression); cout << "表达式的值为:" << result << endl; } cout << "请输入表达式的个数:"; } return 0; }
但,这是错误的,所以我继续修改:用户已经输入了总共的循环次数
GPT说:
如果用户已经输入了总共要执行循环的次数,那么可以在代码中添加一个计数器来控制循环的次数。以下是修改后的代码:
#include <iostream> #include <stack> #include <string> #include <cmath> using namespace std; int youxiancixu(char op) { if (op == '+' || op == '-') return 1; if (op == '*' || op == '/') return 2; if (op == '^') return 3; return 0; } int yunsuan(int a, int b, char op) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; case '^': return pow(a, b); } return 0; } int evaluateExpression(string x) { stack<int> operandStack; stack<char> operatorStack; for (char& c : x) { if (c == ' ') continue; if (isdigit(c)) { operandStack.push(c - '0'); } else if (c == '(') { operatorStack.push(c); } else if (c == ')') { while (!operatorStack.empty() && operatorStack.top() != '(') { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = yunsuan(a, b, op); operandStack.push(result); } if (!operatorStack.empty() && operatorStack.top() == '(') { operatorStack.pop(); } } else { while (!operatorStack.empty() && youxiancixu(c) <= youxiancixu(operatorStack.top())) { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = yunsuan(a, b, op); operandStack.push(result); } operatorStack.push(c); } } while (!operatorStack.empty()) { int b = operandStack.top(); operandStack.pop(); int a = operandStack.top(); operandStack.pop(); char op = operatorStack.top(); operatorStack.pop(); int result = yunsuan(a, b, op); operandStack.push(result); } return operandStack.top(); } int main() { int n; cout << "请输入总共要执行的循环次数:"; if (cin >> n) { cin.get(); // 读取掉回车符 for (int i = 1; i <= n; i++) { string x; cout << "请输入第" << i << "个中缀表达式:"; getline(cin, x); int result = evaluateExpression(x); cout << "表达式的值为:" << result << endl; } } return 0; }
优化:
改了一下变量名,增加了注释,删掉了用户提示。
最终代码
#include <iostream>
#include <stack>
#include <string>
#include <cmath>
using namespace std;
// 定义运算符优先级函数
int youxiancixu(char op) {
if (op == '+' || op == '-')
return 1;
if (op == '*' || op == '/')
return 2;
if (op == '^')
return 3;
return 0;
}
// 定义运算函数
int yunsuan(int a, int b, char op) {
switch (op) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return a / b;
case '^':
return pow(a, b);
}
return 0;
}
// 定义表达式求值函数
int evaluateExpression(string x) {
stack<int> operandStack; // 操作数栈
stack<char> operatorStack; // 运算符栈
for (char& c : x) {
if (c == ' ')
continue;
if (isdigit(c)) { // 如果是数字则入栈到操作数栈
operandStack.push(c - '0');
} else if (c == '(') { // 如果是左括号则入栈到运算符栈
operatorStack.push(c);
} else if (c == ')') { // 如果是右括号,则将栈内运算符进行计算,直到遇到左括号
while (!operatorStack.empty() && operatorStack.top() != '(') {
int b = operandStack.top();
operandStack.pop();
int a = operandStack.top();
operandStack.pop();
char op = operatorStack.top();
operatorStack.pop();
int result = yunsuan(a, b, op);
operandStack.push(result);
}
if (!operatorStack.empty() && operatorStack.top() == '(') {
operatorStack.pop(); // 弹出左括号
}
} else { // 如果是运算符
// 将栈内优先级高于或等于当前运算符的运算符进行计算,直到遇到优先级更低的运算符或左括号
while (!operatorStack.empty() && youxiancixu(c) <= youxiancixu(operatorStack.top())) {
int b = operandStack.top();
operandStack.pop();
int a = operandStack.top();
operandStack.pop();
char op = operatorStack.top();
operatorStack.pop();
int result = yunsuan(a, b, op);
operandStack.push(result);
}
operatorStack.push(c); // 当前运算符入栈
}
}
// 清空栈内剩余的运算符进行计算
while (!operatorStack.empty()) {
int b = operandStack.top();
operandStack.pop();
int a = operandStack.top();
operandStack.pop();
char op = operatorStack.top();
operatorStack.pop();
int result = yunsuan(a, b, op);
operandStack.push(result);
}
return operandStack.top(); // 返回最终计算结果
}
int main() {
int n;
if (cin >> n) { // 输入要执行的循环次数
cin.get(); // 读取掉回车符
for (int i = 1; i <= n; i++) {
string x;
getline(cin, x); // 读取表达式
int result = evaluateExpression(x); // 求值
cout << result << endl; // 输出结果
}
}
return 0;
}
结语
很好!我爱GPT!