Files
Data-Structure/Exercise/Homework3/Q1双栈做法.cpp
e2hang 218a2fb56a Hm3
2025-10-24 09:52:24 +08:00

192 lines
5.5 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
//---------------------------------------------
// 常量定义
//---------------------------------------------
const long long INF = 1LL << 31; // 题目要求结果范围 [-2^31, 2^31)
//---------------------------------------------
// 运算符优先级函数
//---------------------------------------------
// 返回一个运算符的优先级等级(数值越大优先级越高)
int level(char op) {
switch (op) {
case '+': case '-': return 1; // 加减最低
case '*': case '/': return 2; // 乘除中等
case '^': return 3; // 幂最高
default: return 0; // 不是运算符
}
}
//---------------------------------------------
// 判断运算符是否是右结合的
//---------------------------------------------
// 只有幂运算(^是右结合a^b^c 等价于 a^(b^c)
bool rightAssoc(char op) {
return op == '^';
}
//---------------------------------------------
// 安全快速幂函数(带溢出检测)
//---------------------------------------------
// 不允许调用系统 pow所以自己写
// 同时要检测结果是否超过题目要求范围(即 int32 溢出)
long long fastpow(long long a, long long b, bool &valid) {
long long res = 1;
while (b > 0) {
// 如果当前最低位是1需要乘一次
if (b & 1) {
// 判断是否会溢出
if (a != 0 && llabs(res) > (INF - 1) / llabs(a)) {
valid = false;
return 0;
}
res *= a;
}
// 准备平方底数
b >>= 1;
if (b) { // 如果还没结束,再判断一次平方是否安全
if (llabs(a) > (INF - 1) / llabs(a)) {
valid = false;
return 0;
}
a *= a;
}
}
return res;
}
//---------------------------------------------
// 执行一次运算:从两个栈中取出运算符和操作数
//---------------------------------------------
bool apply(stack<long long> &num, stack<char> &op) {
if (num.size() < 2 || op.empty()) return false; // 不够算
long long b = num.top(); num.pop(); // 注意顺序:右操作数
long long a = num.top(); num.pop(); // 左操作数
char c = op.top(); op.pop(); // 运算符
long long res = 0;
switch (c) {
case '+': res = a + b; break;
case '-': res = a - b; break;
case '*': res = a * b; break;
case '/':
if (b == 0) return false; // 除零报错
res = a / b; // 整除自动截尾
break;
case '^': {
if (b < 0) return false; // 题目保证指数非负,但保险起见检测
bool valid = true;
res = fastpow(a, b, valid);
if (!valid) return false; // 幂运算溢出
break;
}
default:
return false; // 非法符号
}
// 检查结果范围
if (res >= INF || res < -INF) return false;
num.push(res);
return true;
}
//---------------------------------------------
// 主计算函数:计算一行表达式
//---------------------------------------------
string calcExpr(const string &s) {
stack<long long> num; // 数字栈
stack<char> op; // 运算符栈
int n = s.size();
for (int i = 0; i < n; ) {
if (isspace(s[i])) { // 跳过空格
i++;
continue;
}
//-------------------------------------
// 处理数字(支持多位整数)
//-------------------------------------
if (isdigit(s[i])) {
long long val = 0;
while (i < n && isdigit(s[i])) {
val = val * 10 + (s[i] - '0');
if (val >= INF) return "INVALID"; // 超过范围
i++;
}
num.push(val);
}
//-------------------------------------
// 处理左括号
//-------------------------------------
else if (s[i] == '(') {
op.push('(');
i++;
}
//-------------------------------------
// 处理右括号:要计算到上一个'('为止
//-------------------------------------
else if (s[i] == ')') {
while (!op.empty() && op.top() != '(') {
if (!apply(num, op)) return "INVALID";
}
if (op.empty()) return "INVALID"; // 括号不匹配
op.pop(); // 弹出 '('
i++;
}
//-------------------------------------
// 处理运算符
//-------------------------------------
else {
char now = s[i];
if (level(now) == 0) return "INVALID"; // 非法字符
// 栈顶运算符如果优先级更高或相同(且不是右结合),就先计算
while (!op.empty() && op.top() != '(' &&
(level(op.top()) > level(now) ||
(level(op.top()) == level(now) && !rightAssoc(now)))) {
if (!apply(num, op)) return "INVALID";
}
op.push(now);
i++;
}
}
//-------------------------------------
// 处理栈中剩余的运算符
//-------------------------------------
while (!op.empty()) {
if (!apply(num, op)) return "INVALID";
}
//-------------------------------------
// 如果数字栈不止一个,说明表达式有问题
//-------------------------------------
if (num.size() != 1) return "INVALID";
// 输出最终结果
return to_string(num.top());
}
//---------------------------------------------
// 主函数:多行输入,每行一个表达式
//---------------------------------------------
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s;
while (getline(cin, s)) {
string ans = calcExpr(s);
cout << ans << "\n";
}
return 0;
}