原则:
对后缀表达式计算的过程中,我们需要暂存还不能马上参与运算的运算数,对这些运算数的管理方法主要是先入后出的原则,即需要使用堆栈对这些暂存的运算数在求职过程中管理。
实现基本过程:
从左到右读入后缀表达式各项,根据读入对象判断执行操作:
- 当读入的是一个运算数,把它被压入栈内;
- 当读入一个运算符,从堆栈中弹出适当数量的运算数,对该运算进行计算,计算结果再压回到栈中;
- 处理完整个后缀表达式之后,堆栈顶上元素是表达式的结果值
运算示例:
后缀表达式的对象(运算数或运算符号)之间需要用空格分割开,运算数为正实数。
1.2 1.3 + 2 4.2 * -
示例程序:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
#define MAXOP 100 /*操作序列最大长度*/
#define INFINITY 1e9 /*代表正无穷*/
typedef double ElementType;
typedef enum
{
num,
opr,
end
} Type; //类型依次对应运算数,运算符,字符串结尾
typedef int Position;
typedef struct SNode *PtrToSNode;
struct SNode
{
ElementType *Data;
Position Top;
int MaxSize;
};
typedef PtrToSNode Stack;
Stack CreateStack(int MaxSize)
{
Stack S = (Stack)malloc(sizeof(struct SNode));
S->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
S->Top = -1;
S->MaxSize = MaxSize;
return S;
}
bool IsFull(Stack S)
{
return (S->Top == S->MaxSize - 1);
}
bool Push(Stack S, ElementType X)
{
if (IsFull(S))
{
printf("栈满");
return false;
}
else
{
S->Data[++(S->Top)] = X;
return true;
}
}
bool ISEmpty(Stack S)
{
return (S->Top == -1);
}
ElementType Pop(Stack S)
{
if (ISEmpty(S))
{
printf("栈空\n");
return -1;
}
else
return (S->Data[(S->Top)--]);
}
Type GetOp(char *Expr, int *start, char *str)
{
/*从*start开始读入下一个对象,并保存在str内*/
int i = 0;
/*跳过表达式前的空格*/
while ((str[0] = Expr[(*start)++]) == ' ')
; //通过while循环去掉空格
while (str[i] != ' ' && str[i] != '\0')
str[++i] = Expr[(*start)++];
if (str[i] == '\0') //如果读到输入的结尾
(*start)--; //退回一步,*start指向结束符
str[i] = '\0'; //结束一个对象的获取
if (i == 0)
return end;
// isdigit函数主要用于检查其参数是否为十进制数字字符。
else if (isdigit(str[0]) || isdigit(str[1]))
return num; //表示此时str中存的是一个数字
else //如果str不是空串,又不是数字
return opr; //表示此时str中存的是一个运算符
}
ElementType PostfixExp(char *Expr)
{ //调用Getop函数读入后缀表达式并求值
Stack S;
Type T;
ElementType Op1, Op2;
char str[MAXOP];
int start = 0;
/*申请一个新堆栈*/
S = CreateStack(MAXOP);
Op1 = Op2 = 0;
//由于相邻数据中间存在空格,所以GetOp()一次只能读入一个数据
while ((T = GetOp(Expr, &start, str)) != end)
{ //当未读到输入结束
if (T == num)
// atof()函数将字符串转化为浮点数
Push(S, atof(str));
else
{
if (!ISEmpty(S))
Op2 = Pop(S);
else
Op2 = INFINITY;
if (!ISEmpty(S))
Op1 = Pop(S);
else
Op2 = INFINITY;
switch (str[0])
{
case '+':
Push(S, Op1 + Op2);
break;
case '*':
Push(S, Op1 * Op2);
break;
case '-':
Push(S, Op1 - Op2);
break;
case '/':
if (Op2 != 0.0) //检测除法分母是否为0
Push(S, Op1 / Op2);
else
{
printf("错误:除法分母为0\n");
Op2 = INFINITY;
}
break;
default:
printf("错误:未知运算符%s\n", str);
Op2 = INFINITY;
break;
}
if (Op2 >= INFINITY)
break;
}
}
if (Op2 < INFINITY) //如果处理完了表达式
if (!ISEmpty(S)) //此时堆栈正常
Op2 = Pop(S); //记录计算结果
else
Op2 = INFINITY; //否则标记错误
free(S); //释放堆栈
return Op2;
}
int main(void)
{
char Expr[MAXOP];
ElementType f;
gets(Expr);
f = PostfixExp(Expr);
if (f < INFINITY)
printf("%.4f\n", f);
else
printf("表达式错误\n");
return 0;
}