Problem Description
算数四则运算的规则是1)先乘除,后加减;2)从左算到右;3)先括号内,后括号外。
由此,算式4+2*3-10/5的计算顺序为4+2*3-10/5=4+6-10/5=4+6-2=8。
给定一个以“#”作为结束符的算式,求出算式的结果。
给出严蔚敏《数据结构(C语言)》中的一段算法描述以作参考:
图1:表达式求值算法
图2:表达式求值算法(续)
图3:表达式求值算法(续)
Input Description
以“#”结尾的表达式,运算数为正整数。每个表达式占一行。
Output Description
输出表达式运算的结果。
Sample Input
4+2*3-10/5# 3*(7-2)# 2*3/2#
Sample Output
8 15 3
Hint
提示:
使用栈来解决本题,很多人都会想到。但怎样建栈,却带来了问题。同样,严书上的代码实际上也给大家带来了问题。看过严书光盘中代码的人应该知道,代码中使用了两个栈,一个是存储运算符的,类型为char;另一个存储运算数,类型为float。而操作两个栈的函数都一样。要知道,除非像C++中使用泛型,C语言中却基本不能实现这样的操作。所以在C语言环境中需要将这两个栈结合在一起。由于char与int有种特别的联系,可以使用int来代替char存储运算符。
总结:
注意灵活运用栈,要是能够学习C++使用template就更好了。可以模拟STL了。
#include <iostream>
using namespace std;
#define MAXSIZE 100
//定义顺序栈
typedef int Status;
typedef int SElemType;
typedef struct
{
SElemType *top;
SElemType *base;
int stacksize;
}SqStack;
unsigned char Prior[7][7] = {
{'>', '>', '<', '<', '<', '>', '>'},
{'>', '>', '<', '<', '<', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>'},
{'<', '<', '<', '<', '<', '=', ' '},
{'>', '>', '>', '>', ' ', '>', '>'},
{'<', '<', '<', '<', '<', ' ', '='},
};
char OPSET[7] = { '+', '-', '*', '/', '(', ')', '#' };
//栈的初始化
void InitStack(SqStack &S)
{
//S.base = new SElemType[MAXSIZE];
S.base = (SElemType*)malloc(100 * sizeof(SElemType));
if (!S.base)
{
return;
}
S.top = S.base;
S.stacksize = MAXSIZE;
}
//入栈
void Push(SqStack &S, SElemType c)
{
if (S.top - S.base >= S.stacksize)//栈满了但运算还要继续,就重新开辟内存
{
S.base = (SElemType*)realloc(S.base, (S.stacksize + 10) * sizeof(SElemType));
if (!S.base)//如果base为空分配内存失败
{
return;
}
S.stacksize += 10;
}
*(S.top)++ = c;
}
//获取栈顶元素
Status GetTop(SqStack &S)
{
SElemType e;
if (S.top == S.base)
{
return 0;
}
e = *(S.top-1);
return e;
}
//判断是否为运算符
Status In(char c, char str[])
{
int i = 0;
while (c != str[i])
{
i++;
if (i > 7)
{
break;
}
}
if (i < 7)
{
return 1;
}
return 0;
}
//判断优先级
Status precede(int a, char b)
{
int i = 0;
int j = 0;
while (OPSET[i] != a)
{
i++;
}
while (OPSET[j] != b)
{
j++;
}
return Prior[i][j];
}
void Pop(SqStack &S, int &e)
{
if (S.base == S.top)
{
return;
}
e = *(--S.top);
}
Status Operate(int a, int b, int c)
{
switch (b)
{
case '+':
return a + c;
case '-':
return a - c;
case '*':
return a * c;
case '/':
return a / c;
}
}
void strcat(char *str1, char *str2)//字符串连接函数,把字符串str2连接到str1后
{
int i = 0, j = 0;
while (str1[i] != '\0')
{
i++;
}
while (str2[j] != '\0')
{
str1[i++] = str2[j++];
}
str1[i] = '\0';
}
Status atoi(char *c)//把字符串转为数字
{
int data = 0, d = 0;
int i = 0;
while (c[i] != '\0')
{
data = data * 10 + c[i] - '0';
i++;
}
return data;
}
char EvaluateExpression(char *MyExpression)
{
//算术表达式求值的算符优先算法
SqStack OPTR;//运算符栈,字符元素
SqStack OPND; //运算数栈,实数元素
InitStack(OPTR);//初始化运算符栈
Push(OPTR, '#');//将#压入运算符栈
InitStack(OPND);
char TempData[20];
int Data, a, b;
char *c, Dr[2];
int x, theta;
c = MyExpression;
TempData[0] = '\0';
while (*c != '#' || GetTop(OPTR) != '#')
{
if (!In(*c, OPSET))//判断是否为运算符,(不是运算符入栈)
{
Dr[0] = *c;
Dr[1] = '\0';
strcat(TempData, Dr);//把Dr所指向的字符串追加到TempData字符串结尾
c++;//前移
if (In(*c, OPSET))
{
Data = atoi(TempData);// 把字符串转换为int。
Push(OPND, Data);//入栈
TempData[0] = '\0';
}
}
else//如果是数字元素
{
switch (precede(GetTop(OPTR), *c))
{
case '<'://栈顶元素优先级低
Push(OPTR, *c);
c++;
break;
case '='://去掉括号并接收下一个字符
Pop(OPTR, x);
c++;
break;
case '>'://将运算结果入栈
Pop(OPTR, theta);
Pop(OPND, b);
Pop(OPND, a);
Push(OPND, Operate(a, theta, b));//运算
break;
}
}
}
return GetTop(OPND);
}
int main()
{
char str[100];
while (scanf("%s", str) != EOF)
{
printf("%d\n", EvaluateExpression(str));
}
return 0;
}
此处加另外一种算法
#define _CRT_SECURE_NO_WARNINGS 1
#include <stack>
#include <iostream>
#include <string.h>
using namespace std;
#define MAXSIZE 100
char Prior[7][7] = {
//+, -, *, /, (, ), #
{'>', '>', '<', '<', '<', '>', '>'},
{'>', '>', '<', '<', '<', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>'},
{'<', '<', '<', '<', '<', '=', ' '},
{'>', '>', '>', '>', ' ', '>', '>'},
{'<', '<', '<', '<', '<', ' ', '='}
};
char OPSET[7] = { '+', '-', '*', '/', '(', ')', '#' };
stack<int>Num;//运算数
stack<char>Symbol;//符号
char str[MAXSIZE];//
bool IsNum(char ch)
{
if (ch >= '0' && ch <= '9')
{
return true;
}
return false;
}
int GetSymbolnum(char ch)
{
for (int i = 0; i < 7; i++)
{
if (ch == OPSET[i])
{
return i;
}
}
}
int FindNum(int &i)
{
int mun = 0;
int n = 1;
while (IsNum(str[i]))
{
mun = mun * n + (str[i] - '0');
n = 10;
i++;
}
return mun;
}
int Calculate(int b, char c, int a)
{
if (c == '+')
{
return b + a;
}
else if (c == '-')
{
return b - a;
}
else if (c == '*')
{
return b * a;
}
else if (c == '/')
{
return b / a;
}
}
void Operation()
{
int length = strlen(str);
if (str[length - 1] != '#')
{
cout << "输入表达式尾部没有#" << endl;
return;
}
Symbol.push('#');
int i = 0;
while (!Symbol.empty())//当Symbol为空停止运算
{
if (IsNum(str[i]))
{
Num.push(FindNum(i));
}
else//就是操作符
{
int x = GetSymbolnum(Symbol.top());
int y = GetSymbolnum(str[i]);
switch (Prior[x][y])
{
case '<':
{
Symbol.push(str[i]);
i++;
break;
}
case '>':
{
int a = Num.top();
Num.pop();
int b = Num.top();
Num.pop();
char c = Symbol.top();
Symbol.pop();
int d = Calculate(b, c, a);
Num.push(d);
break;
}
case '=':
{
Symbol.pop();
i++;
break;
}
}
}
}
cout << Num.top() << endl;
}
int main()
{
while (scanf("%s", str) != EOF)
{
Operation();
}
return 0;
}