一、题目
输入算术表达式,可包含空格,检查算术表达式的合法性,若算术表达式不合法,打印错误类型,若合法,则进行运算,打印计算结果。
二、算法
1. 将输入的算术表达式字符串去除空格。
2. 检查输入的算术表达式的合法性,判断算式首字符是否合法(只能是前括号或正负号),判断括号是否匹配,判断连续字符是否合法(运算符后面可跟左括号,右括号后面可跟运算符,左括号后面可跟加减号表正负,左右括号之间不能直接相连,数字后面不能直接跟左括号)。
3. 构造符号栈和数据栈对合法的算术表达式进行计算,计算的过程就是从数据栈取出两个数据和符号栈取出一个数据,然后计算得到一个结果,再将结果压入数据栈。
三、代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
vector<char> g_opt = { '+', '-', '*', '/'};
void RemoveSpaces(char* input)
{
for (int i = 0; i < strlen(input); ++i)
{
if (input[i] == ' ')
{
for (int j = i; j < strlen(input); ++j)
{
input[j] = input[j + 1];
}
--i;
}
}
}
bool CheckInput(char* input)
{
stack<char> bracket; // 用于判断括号的合法性
for (int i = 0; i < strlen(input); ++i)
{
if (!isdigit(input[i]))
{
if (find(g_opt.begin(), g_opt.end(), input[i]) == g_opt.end()
&& input[i] != '(' && input[i] != ')')
{
cout << "存在非法字符 " << input[i];
return false;
}
if (input[i] == '(')
{
bracket.push(input[i]);
}
else if (input[i] == ')')
{
if (bracket.empty())
{
cout << "括号不匹配";
return false;
}
else
{
bracket.pop();
}
}
// 第一个字符必须是数字或正负号或左括号
if (i == 0 && input[i] != '+' && input[i] != '-' && input[i] != '(')
{
cout << "首字符错误";
return false;
}
if (!isdigit(input[i + 1]))
{
if (input[i] == '(')
{
// 左括号后面可以跟加减表示正负
if (input[i + 1] == '*' || input[i + 1] == '/' || input[i + 1] == ')')
{
cout << "出现连续符号 " << input[i + 1];
return false;
}
}
else if (input[i] == ')')
{
// 有括号后面不能直接跟前括号,可以跟操作符
if (input[i + 1] == '(')
{
cout << "出现连续符号 " << input[i + 1];
return false;
}
}
else
{
// 操作符后面可以跟左括号
if (input[i + 1] != '(')
{
cout << "出现连续符号 " << input[i + 1];
return false;
}
}
}
}
else
{
// 数字后面不能直接跟左括号
if (input[i + 1] == '(')
{
cout << "括号位置错误 " << input[i + 1];
return false;
}
}
}
if (!bracket.empty())
{
cout << "括号不匹配";
return false;
}
return true;
}
bool PopCal(stack<int>& datas, stack<char>& symbols)
{
if (datas.size() < 2 || symbols.empty())
return false;
if (symbols.top() == '(')
{
symbols.pop();
return false;
}
int x = datas.top();
datas.pop();
int y = datas.top();
datas.pop();
char opt = symbols.top();
symbols.pop();
int res = (unsigned int)-1;
if (opt == '+')
res = x + y;
else if (opt == '-')
res = x - y;
else if (opt == '*')
res = x * y;
else if (opt == '/')
res = x / y;
datas.push(res);
return true;
}
int Calculate(char* input)
{
// 数据栈和符号栈
stack<int> datas;
stack<char> symbols;
int flag = 1; // 1表示正,-1表示负数
for (int i = 0; i < strlen(input); ++i)
{
if (isdigit(input[i]))
{
// 将连续数字字符转为整型数据存入数据栈
string digit = "";
digit += input[i];
while (isdigit(input[i + 1]))
{
++i;
digit += input[i];
}
int num = atoi(digit.c_str());
datas.push(num * flag);
flag = 1;
// 数据压栈后发现栈顶是乘除号,直接进行计算
if (!symbols.empty() && (symbols.top() == '*' || symbols.top() == '/'))
PopCal(datas, symbols);
}
else
{
// 左括号的优先级最高
if (input[i] == '(')
{
symbols.push(input[i]);
continue;
}
// 判断负号
if (i == 0 || input[i - 1] == '(')
{
if (input[i] == '-')
flag = -1;
continue;
}
if (input[i] == '*' || input[i] == '/')
{
// 乘除符号直接压入符号栈
symbols.push(input[i]);
}
else if (input[i] == '+' || input[i] == '-')
{
// 若符号栈存有加减号未计算,先计算再将加减号压栈
if (!symbols.empty() && (symbols.top() == '+' || symbols.top() == '-'))
{
PopCal(datas, symbols);
}
symbols.push(input[i]);
}
else if (input[i] == ')')
{
if (symbols.top() == '(')
{
// 表示括号括住了数字,而不是表达式
symbols.pop();
}
else
{
// 循环出栈计算,直到遇到左括号
while (PopCal(datas, symbols))
{}
}
}
}
}
// 循环出栈计算
while (PopCal(datas, symbols))
{}
return datas.top();
}
int main()
{
while (1)
{
char input[128];
cout << "请输入算术表达式:";
fgets(input, sizeof(input), stdin);
input[strlen(input) - 1] = 0;
RemoveSpaces(input);
if (strcmp(input, "exit") == 0)
break;
if (!CheckInput(input))
{
cout << ",表达式输入格式错误,请重新输入!" << endl;
continue;
}
int res = Calculate(input);
cout << input << " = " << res << endl;
}
return 0;
}