算术表达式的求值
[问题描述]
一个算术表达式是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。假设操作数是正实数,运算符只含加减乘除等四种运算符,界限符有左右括号和表达式起始、结束符“#”,如:#(7+15)*(23-28/4)#。引入表达式起始、结束符是为了方便。编程利用“运算符优先法”求算术表达式的值。
[基本要求]
(1) 从键盘或文件读入一个合法的算术表达式,输出正确的结果。
(2) 显示输入序列和栈的变化过程。
(3) 考虑算法的健壮性,当表达式错误时,要给出错误原因的提示。
上一篇实现交互式
简单算术表达式的求值(待更新功能,暂无解析)
需要的头文件
#include <fstream>
#include<string>
#include<cmath>
#include<iostream>
using namespace std;
需要用到的结构:2个栈
//操作符
typedef struct CStackNode {
char data;
struct CStackNode *next;
} CStackNode, *CLinkStack;
bool Init(CLinkStack &cL) {
cL = NULL;
return true;
}
//入栈
bool Push(CLinkStack &L, char e) {
CLinkStack temp = new CStackNode;
temp->data = e;
temp->next = L;
L = temp;
return true;
}
//出栈
bool Pop(CLinkStack &L, char & e) {
if (!L) return false;
e = L->data;
CLinkStack temp = L;
L = L->next;
delete temp;
return true;
}
//取顶
char getTop(CLinkStack L) {
if (L) return L->data;
else return false;
}
//判空
bool StackEmpty(CLinkStack L) {
if (!L) return true;
else return false;
}
//清空
bool clearAll(CLinkStack L) {
char e;
while (!StackEmpty(L)) {
Pop(L, e);
}
return true;
}
//遍历
void GetAll(CLinkStack S) {// 递归遍历,分治法
if (S == NULL) {
return;
}
else {
cout << S->data << " ";
GetAll(S->next);
}
}
//数字
typedef struct IStackNode {
double data;
struct IStackNode *next;
} IStackNode, *ILinkStack;
bool Init(ILinkStack & cL) {
cL = NULL;
return true;
}
bool Push(ILinkStack &L, double e) {
ILinkStack temp = new IStackNode;
temp->data = e;
temp->next = L;
L = temp;
return true;
}
bool Pop(ILinkStack &L, double & e) {
if (!L) return false;
e = L->data;
ILinkStack temp = L;
L = L->next;
delete temp;
return true;
}
double getTop(ILinkStack L) {
if (L) return L->data;
else return false;
}
bool StackEmpty(ILinkStack L) {
if (!L) return true;
else return false;
}
bool clearAll(ILinkStack L) {
double e;
while (!StackEmpty(L)) {
Pop(L, e);
}
return true;
}
void GetAll(ILinkStack S) {// 递归遍历,分治法
if (S == NULL) {
return;
}
else {
cout << S->data << " ";
GetAll(S->next);
}
}
//判断符号是否为规定的操作符
bool In(char c) {
// if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' || c == '#'||c=='.'||c=='('||c==')')
if (c >= '0' &&c <= 9 + '0')
return false;
else
return true;
}
//判断字符
bool TrueIn(char c) {
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' || c == '#' || c == '.')
return true;
else
return false;
}
//判断优先级
char Precede(char a, char b) {//按照表规定
switch (a) {
case '+':
{
switch (b) {
case '+':return '>';
case '-':return '>';
case '*':return '<';
case '/':return '<';
case '(':return '<';
case ')':return '>';
case '#':return '>';
}
}
break;
case '-':
{
switch (b) {
case '+':return '>';
case '-':return '>';
case '*':return '<';
case '/':return '<';
case '(':return '<';
case ')':return '>';
case '#':return '>';
}
}
break;
case '*':
{
switch (b) {
case '+':return '>';
case '-':return '>';
case '*':return '>';
case '/':return '>';
case '(':return '<';
case ')':return '>';
case '#':return '>';
}
}
break;
case '/':
{
switch (b) {
case '+':return '>';
case '-':return '>';
case '*':return '>';
case '/':return '>';
case '(':return '<';
case ')':return '>';
case '#':return '>';
}
}
break;
case '(':
{
switch (b) {
case '+':return '<';
case '-':return '<';
case '*':return '<';
case '/':return '<';
case '(':return '<';
case ')':return '=';
// case '#':return ' ';
}
}
break;
case ')':
{
switch (b) {
case '+':return '>';
case '-':return '>';
case '*':return '>';
case '/':return '>';
// case '(':return ' ';
case ')':return '>';
case '#':return '>';
}
}
break;
case '#':
{
switch (b) {
case '+':return '<';
case '-':return '<';
case '*':return '<';
case '/':return '<';
case '(':return '<';
// case ')':return ' ';
case '#':return '=';
}
}
break;
}
}
//计算
double Operate(double a, char c, double b) {
switch (c) {
case '+': return (a + b); break;
case '-':return (a - b); break;
case '*':return (a*b); break;
case '/':return (a / b); break;
}
}
//匹配重点
double EvaluateExpression(char data[])
{
CLinkStack optr;//操作符栈
Init(optr);
ILinkStack opnd;//数字栈
Init(opnd);
char ch, theta;
int mark = 0;
int mark_weishu = 0;//小数部分标志
int pointOccurTime = 0;
int currentPos = 0;
ch = data[currentPos++];//ch = getchar();
while (ch != '#')
{
return -1;
}
Push(optr, ch);//'#'表示起始点
//遍历符号栈结果
cout << "符号栈中的结果" << ends;
GetAll(optr);
cout << endl;
ch = data[currentPos++];// ch = getchar();
double a, b;
int numberTime = 0;
L:while (ch != '#' || getTop(optr) != '#') //表达式没有扫描完毕或OPTR栈定元素不为#
{
if (ch != '\n') {
if (!In(ch))
{//输入数字,只对整数操作
if (numberTime && mark == 0)//二位数或更多位数
{//不是第一位且前一位也为数字
double e;
Pop(opnd, e);
b = e * 10 + (ch - '0');
Push(opnd, b);
ch = data[currentPos++]; // ch = getchar();
}
else if (numberTime && mark == 1)
{//不是第一位且前一位不为数字,小数部分
double e, numbertemp;
Pop(opnd, e);
numbertemp = (ch - '0');
++mark_weishu;
b = e + numbertemp * pow(10, (mark_weishu)*(-1));
Push(opnd, b);
ch = data[currentPos++];// ch = getchar();
}
else {//第一位整数
int n = ch - '0';
Push(opnd, n);
ch = data[currentPos++]; // ch = getchar();
numberTime = 1;
}
//遍历数字栈结果
cout << "数字栈中的结果" << ends;
GetAll(opnd); cout << endl;
}
else //字符
{
if (TrueIn(ch)) {//使用正确的符号
if (numberTime != 0 && ch == '.') {
pointOccurTime += 1;
if (pointOccurTime < 2) {
mark = 1;
ch = data[currentPos++];// cin >> ch;
goto L;
}
else
goto L2;
}
else
{
//先考虑匹配问题
switch (getTop(optr))
{
case '#': {
if (ch != '('&&ch != '#'&&ch != '+'&&ch != '-'&&ch != '*'&&ch != '/')
goto L0;
break;
}
case '(': {
if (ch != '+'&&ch != '-'&&ch != '*'&&ch != '/'&&ch != ')'&&ch!='(' )
goto L0;
break;
}
case ')': {
if (ch != '#'&&ch != '+'&&ch != '-'&&ch != '*'&&ch != '/')
goto L0;
break;
}
case '+': {
if (ch != '#'&&ch != '+'&&ch != '-'&&ch != '*'&&ch != '/'&&ch!='(')
goto L0;
break;
}
case '-': {
if (ch != '#'&&ch != '+'&&ch != '-'&&ch != '*'&&ch != '/'&&ch != '(')
goto L0;
break;
}
case '*': {
if (ch != '#'&&ch != '+'&&ch != '-'&&ch != '*'&&ch != '/'&&ch != '(')
goto L0;
break;
}
case '/': {
if (ch != '#'&&ch != '+'&&ch != '-'&&ch != '*'&&ch != '/'&&ch != '(')
goto L0;
break;
}
}
//正式比较运算顺序
numberTime = 0;
pointOccurTime = 0;
mark = 0;
mark_weishu = 0;
switch (Precede(getTop(optr), ch))
{
case '<'://后面的大,压入
{
Push(optr, ch);
//遍历符号栈结果
cout << "符号栈中的结果" << ends;
GetAll(optr);
cout << endl;
//遍历数字栈结果
cout << "数字栈中的结果" << ends;
GetAll(opnd); cout << endl;
ch = data[currentPos++];//cin >> ch;
break;
}
case '>'://后面的小,输入前面的结果
{
if (!StackEmpty(opnd) && !StackEmpty(opnd->next)) {
Pop(optr, theta);
Pop(opnd, a);
Pop(opnd, b);
Push(opnd, Operate(b, theta, a));// b operate a的结果
//遍历符号栈结果
cout << "符号栈中的结果" << ends;
GetAll(optr);
cout << endl;
//遍历数字栈结果
cout << "数字栈中的结果" << ends;
GetAll(opnd); cout << endl;
}
else
goto L0;
break;
}
case '=':Pop(optr, ch);
ch = data[currentPos++];//cin >> ch;
break;
}
//考虑到有3个书上没规定,但是会影响的顺序
if ((getTop(optr) == '('&&ch == '#') || (getTop(optr) == ')'&&ch == '(') || (getTop(optr) == '#'&&ch == ')'))
goto L0;
//遍历符号栈结果
cout << "符号栈中的结果" << ends;
GetAll(optr);
cout << endl;
}
}
else
goto L1;//没用使用正确的符号格式就返回-2
}
}
else {//遇到换行符号
ch = data[currentPos++];// ch = getchar();
goto L;
}
}
return getTop(opnd);
L0: return -1;//符号匹配不对
L1: return -2;//符号类型不对
L2: return -3;//输入了多余的小数点
}
//主函数
int main() {
char data[100];
const char *p;
string line;
fstream in("C:\\Users\\Lenovo\\Desktop\\data.txt", ios::in);
//我放在电脑桌面上
if (in) // 有该文件
{
L3: while (getline(in, line)) // line中不包括每行的换行符
{
cout << line << endl;
p = line.c_str();
int i;
for (i = 0; i < line.length(); i++) {
if (p[i] >= 0 && p[i] <= 127)//ASCILL码范围内
data[i] = p[i];
else {
cout << "符号类型不对,请进行切换成英文格式的括号等检查工作" << endl;
memset(data, '\0', sizeof(data));
goto L3;
}
}
data[i] = '\0';
cout << "字符串信息" << ends;
for (i = 0; i < line.length(); i++) {
cout<<data[i];
}cout << endl;
double result = EvaluateExpression( data);
if (result != -2 && result != -1 && result != -3) {
if ((result - (int)result) != 0)
printf("result=%lf\n", result);
else
cout << (int)result << endl;
}
else if (result == -1) {
cout << "符号匹配不对,请进行符号匹配检查等工作" << endl;
memset(data, '\0', sizeof(data));
continue;
}
else if (result == -2) {
memset(data, '\0', sizeof(data));
cout << "符号类型不对,请进行切换成英文格式的括号等检查工作" << endl;
continue;
}
else if (result == -3) {
memset(data, '\0', sizeof(data));
cout << "输入了多余的小数点,请进行检查工作" << endl;
continue;
}
memset(data, '\0', sizeof(data));
}
}
in.close();
system("pause");
return 0;
}