数据结构——后缀表达式

一、基本概念

中缀表达式

        操作符在运算数之间(如:1 + 1);

后缀表达

        操作符以后缀形式位于两个运算数后(如:1 1 +)。

        中缀表达式常用括号来将操作数与相应的操作符括起来,用此来指示运算的次序。

二、中缀表达式转为后缀表达式规则

从左往右一次遍历中缀表达式的各个字符

(需要一个操作栈来存放操作符与括号;还要一个运算数栈来存放运算数)

1、字符为 运算数 :

直接送入后缀表达式

2、字符为 左括号 :

直接入栈,优先级降维最低

3、字符为 右括号 :

直接出栈,并将出栈字符依次送入后缀表达式,直到栈顶元素为左括号(左括号也要出栈)

4、字符为 操作符 :

若栈为空栈,则直接入栈;

若栈不为空,判断栈顶操作符,若栈顶操作符优先级低于该操作符,该操作符入栈;否则一直出栈,并将出栈字符依次送入后缀表达式,直到栈空或栈顶操作符优先级低于该操作符,该操作符再入栈。

总结:只要满足栈空 / 优先级高于栈顶操作符,停止出栈,直接入栈

5、中缀表达式遍历完成,栈中可能还有字符未输出,故需要判断栈空。

三、后缀表达式的计算

从左往右依次遍历后缀表达式

1、字符为 运算数:

直接入栈

2、字符为 操作符:

连续出栈两次,并进行相应的计算,将计算结果入栈

四、算法实现

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
#include<ctype.h>

#define ERROR 0
#define OK 1
#define STACK_INT_SIZE 10  /*存储空间初始分配量*/
#define STACKINCREMENT 5  /*存储空间分配增量*/
#define M 50

typedef char ElemType; /*定义字符数据类型*/
typedef double ElemType2;  /*定义运算数数据类型*/

/*字符栈*/
typedef struct {
    ElemType* base;
    ElemType* top;
    int stacksize;
}SqStack;

/*运算数栈*/
typedef struct {
    ElemType2* base;
    ElemType2* top;
    int stacksize;
}NStack;

int InitStack(SqStack* S);                      /*构造空栈*/
int Push(SqStack* S, ElemType e);               /*入栈*/
int Pop(SqStack* S, ElemType* e);               /*出栈*/
int StackEmpty(SqStack* s);                     /*栈空判断*/
void in2post(ElemType* str, ElemType* p);       /*中缀表达式转后缀表达式*/
double cal_post(char* str);                     /*计算后缀表达式*/

/*字符栈初始化*/
int InitStack(SqStack* S) 
{
    S->base = (ElemType*)malloc(STACK_INT_SIZE * sizeof(ElemType));
    if (!S->base)
        return ERROR;       //分配失败
    S->top = S->base;
    S->stacksize = STACK_INT_SIZE;
    return OK;
}/*InitStack*/

/*初始化运算数栈*/
int InitStack_N(NStack* S) 
{
    S->base = (ElemType2*)malloc(STACK_INT_SIZE * sizeof(ElemType2));
    if (!S->base)
        return ERROR;       //分配失败
    S->top = S->base;
    S->stacksize = STACK_INT_SIZE;
    return OK;
}

/*字符栈入栈*/
int Push(SqStack* S, ElemType e) 
{
    //判断栈满
    if (S->top - S->base >= S->stacksize) 
    {
        S->base = (ElemType*)realloc(S->base, (S->stacksize + STACKINCREMENT) * sizeof(ElemType));
        if (NULL == S->base)  //分配失败
            return ERROR;
        S->top = S->base + S->stacksize; //?是什么相加
        S->stacksize = S->stacksize + STACKINCREMENT;
    }
    *S->top = e;
    S->top++;
    return OK;
}

/*运算数栈入栈*/
int Push_N(NStack* S, ElemType2 e) 
{
    if (S->top - S->base >= S->stacksize) 
    {
        S->base = (ElemType2*)realloc(S->base, (S->stacksize + STACKINCREMENT) * sizeof(ElemType2));
        if (NULL == S->base)
            return ERROR;
        S->top = S->base + S->stacksize;
        S->stacksize = S->stacksize + STACKINCREMENT;
    }
    *S->top = e;
    S->top++;
    return OK;
}

/*字符栈出栈*/
int Pop(SqStack* S, ElemType* e) 
{
    //判断栈空
    if (S->top == S->base)
        return ERROR;
    S->top--;
    *e = *S->top;
    return OK;
}/*Pop*/

/*运算数栈出栈*/
int Pop_N(NStack* S, ElemType2* e) 
{
    if (S->top == S->base)
        return ERROR;
    S->top--;
    *e = *S->top;
    return OK;
}

/*判断栈空*/
int StackEmpty(SqStack* s) 
{
    if (s->top == s->base)
        return OK;
    return ERROR;
}/*StackEmpty*/

//str为待转换的中缀表达式字符串,p为转换后的后缀表达式字符串
void in2post(ElemType* str, ElemType* p) {   /*infix to postfix*/
    SqStack s;
    InitStack(&s);   //初始化一个空字符栈
    ElemType e;
    int i;
    int j = 0;
    for (i = 0; i < strlen(str); i++)  //遍历中缀表达式
    {
        //遇到数字和小数点直接输出
        //使用循环完整接收一个运算数
        while (isdigit(str[i]) || '.' == str[i])
        {
            p[j++] = str[i++];
            if (!isdigit(str[i]) && '.' != str[i])
                p[j++] = ' ';   //一个数字完整输出后使用空格与其它运算符或数字分隔开
        }

        //遇到左括号直接入栈
        if ('(' == str[i])
            Push(&s, str[i]);

        //遇到右括号直接出栈,直到栈顶为左括号
        if (')' == str[i])
        {
            while ('(' != *(s.top - 1))
            {
                Pop(&s, &e);
                p[j++] = e;
                p[j++] = ' ';
            }
            Pop(&s, &e);  //左括号出栈但不输出
        }

        //遇到+或—
        //1.栈空/栈顶为左括号:直接入栈
        //2.否则一直出栈,直到栈空/栈顶为左括号,再入栈
        if ('+' == str[i] || '-' == str[i])
        {
            while (!StackEmpty(&s) && '(' != *(s.top - 1))
            {
                Pop(&s, &e);
                p[j++] = e;
                p[j++] = ' ';
            }
            Push(&s, str[i]);
        }

        //遇到*或/
        //1.栈空/栈顶为左括号/栈顶操作符为+ or -:直接入栈
        //2.否则一直出栈,直到满足1,再入栈
        if ('*' == str[i] || '/' == str[i] || '%' == str[i])
        {
            while (!StackEmpty(&s) && '(' != *(s.top - 1) && '+' != *(s.top - 1) && '-' != *(s.top - 1))
            {
                Pop(&s, &e);
                p[j++] = e;
                p[j++] = ' ';
            }
            Push(&s, str[i]);
        }
    }
    //中缀表达式遍历完成,还需检查栈中是否有未输出字符
    //判断栈空,非空则直接出栈并输出(左括号不用输出)
    while (!StackEmpty(&s)) {
        Pop(&s, &e);
        if ('(' != e)
        {
            p[j++] = e;
            p[j++] = ' ';
        }
    }
    p[--j] = '\0';
}/*infix2postfix*/

//str为待计算的后缀表达式,返回值为计算结果
double cal_post(char* str)  /*计算后缀表达式*/
{  
    int i;
    ElemType2 e, a, b;
    char d[M];
    NStack n;
    InitStack_N(&n);   //初始化一个运算数栈保存运算数
    for (i = 0; i < strlen(str); i++)
    {
        int j = 0;
        while (isdigit(str[i]) || '.' == str[i])
        {
            d[j++] = str[i++];
            d[j] = '\0';
            if (!isdigit(str[i]) && '.' != str[i])
            {
                e = atof(d);   //使用atof()将字符串形式的运算数转换为double型数据
                Push_N(&n, e);   //运算数入栈
            }
        }
        switch (str[i])
        {
        case '+':
            Pop_N(&n, &b);
            Pop_N(&n, &a);
            Push_N(&n, a + b);
            break;
        case '-':
            Pop_N(&n, &b);
            Pop_N(&n, &a);
            Push_N(&n, a - b);
            break;
        case '*':
            Pop_N(&n, &b);
            Pop_N(&n, &a);
            Push_N(&n, a * b);
            break;
        case '/':
            Pop_N(&n, &b);
            Pop_N(&n, &a);
            Push_N(&n, a / b);
            break;
        }
    }
    Pop_N(&n, &e);
    return e;
}/*calculate_postfix*/

int main()
{
    char str[M];
    char post[M];
    int i;
    printf("\n输入一串中缀表达式:\n");
    gets(str);
    printf("\n对应的后缀表达式:\n");
    in2post(str, post);
    printf("%s", post);
    printf("\n\n计算后缀表达式:\n");
    printf("%f", cal_post(post));
    return 0;
}

五、算法改进

1、判断中缀表达式是否合法

2、运算数为非负数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值