中缀表达式转后缀表达式

平常我们所用的标准四则运算表达式,如:1+((2+3)*4)-5,叫做中缀表达式,今天介绍一种不需要括号的后缀表达法,我们也把它称为逆波兰式(Reverse Polish Notation ,RPN)表示。后缀表示式为栈数据结构的一种应用。

  • 中缀表达式: 1+((2+3)*4)-5
  • 后缀表达式: 123+4*+5-

其中上面的中缀表达式和后缀表达式等价。

后缀表达式遵循以下规则

  1. 从左到右遍历中缀表达式的每一个数字和符号。
  2. 若是数字就输出,即成为后缀表达式的一部分。
  3. 如果是符号,则判断其与栈顶符号的优先级,是右括号已有栈顶符号优先级(乘除优于加减)大于等于此符号则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。

那么怎么将中缀表达式转化为后缀表达式呢?

1)创建一个堆栈

2)从左往右顺序获取中缀表达式

2.1)遇到数字,直接输出

2.2)运算符

a:遇到左括号 '(' 直接入栈

b:遇到右括号 '(',将堆栈中左括号之前的元素全部压出堆栈。(PS:同时左括号也压出堆栈,但是我们并不打印输出)

c:遇到乘号 'x' 或者除号 '/' 直接入栈,直到遇到比它优先级更低的运算符,并以此压出堆栈。

d:遇到加号 '+' 或者减号 '-' 。如果此时是空栈,那么直接压入堆栈,否则,需要将栈中优先级高的运算符号依次压出堆栈(这里需要注意的是,如果堆栈中除了比它优先级高的运算符之外还有同等优先级的运算符,也要依次压出堆栈)直到栈变为空或者遇到左括号为止。

e:最后,获取完毕,将剩余的运算符号依次压出堆栈。

代码如下:
 

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<ctype.h>
#define MAX_SIZE 100

typedef int Elemtype;
typedef struct SNode{
    Elemtype *base; //栈底指针
    Elemtype *top; //栈顶指针
    int StackSize;
}SNode, *Stack;

void InitStack(Stack S)
{
    S->base = (Elemtype *)malloc(sizeof(Elemtype) * MAX_SIZE);
    assert(S->base != NULL);
    S->top = S->base;
    S->StackSize = MAX_SIZE;
}
//每次push后保持当前栈顶元素为空
void Push(Stack S, Elemtype c){
    if((S->top - S->base) >= S->StackSize){
        S->base = (Elemtype *)realloc(S->base, S->StackSize + MAX_SIZE);
        assert(S->base != NULL);
        S->top = S->base + MAX_SIZE;
    }
    *S->top = c;
    S->top++; 
}

int Stacklength(Stack S){
    return (S->top - S->base);
}
//Function: 栈顶指针指向下一位元素,并且由地址p返回被pop的元素具体大小
int Pop(Stack S, Elemtype *p){
    if(Stacklength(S) == 0){
        return 0;
    }
    S->top--;
    *p = *S->top; //利用地址p返回当前的栈顶元素
    return 1;
}


void Change(char *str, Stack S){
    InitStack(S);
    int i = 0;
    Elemtype c;
    while(str[i] != '\0'){
        if(isdigit(str[i])){
            printf("%c", str[i]);
        }
        else if(str[i] == '+' || str[i] == '-'){
                if(!Stacklength(S)){
                    Push(S, str[i]);
                }
                else {
                    do {
                        Pop(S, &c);
                        if(c == '('){
                            Push(S, c);
                        }
                        else {
                            printf("%c", c);
                        }
                    } while(Stacklength(S) && c != '(');
                    Push(S, str[i]);
                }
            }

        else if(str[i] == '('){
            Push(S, str[i]);
        }
        else if(str[i] == ')'){
            Pop(S, &c);
            while(c != '('){
                printf("%c", c);
                Pop(S, &c);
            }
        }
        else if(str[i] == '*' || str[i] =='/'){
            Push(S, str[i]);
        }
        else{
            printf("Print Error\n");
        }
        i++;
    }
    while(Stacklength(S)){
        Pop(S, &c);
        printf("%c", c);
    }
}

int main(){
    char str[105];
    Stack S = (Stack)malloc(sizeof(SNode));
    fgets(str, MAX_SIZE, stdin);
    str[strlen(str) - 1] = '\0';
    Change(str, S);
    return 0;
}


本文所用代码主体参考数据结构题目笔记-03-中缀表达式转为后缀表达式 C语言 - 掘金 (juejin.cn)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值