利用堆栈求后缀表达式

原则:

对后缀表达式计算的过程中,我们需要暂存还不能马上参与运算的运算数,对这些运算数的管理方法主要是先入后出的原则,即需要使用堆栈对这些暂存的运算数在求职过程中管理。

实现基本过程:

从左到右读入后缀表达式各项,根据读入对象判断执行操作:

  1. 当读入的是一个运算数,把它被压入栈内;
  2. 当读入一个运算符,从堆栈中弹出适当数量的运算数,对该运算进行计算,计算结果再压回到栈中;
  3. 处理完整个后缀表达式之后,堆栈顶上元素是表达式的结果值

运算示例:

后缀表达式的对象(运算数或运算符号)之间需要用空格分割开,运算数为正实数。

 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;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

brepot

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值