Stack | 栈实现 —— 后缀表达式

目录

 

一、后缀表达式

二、中缀表达式转后缀表达式

1、过程详解

2、核心算法

3、代码实现

 完整代码


一、后缀表达式

我们通常见到的计算表达式都是中缀表达式,操作数分布在二元操作符的两端如:a+b。

而后缀表达式是这样子表示的:ab+。

后缀表达式又叫逆波兰式,表达式中操作符放在对应操作数之后,后缀表达式形式上相比中缀更加简略,因为它去除了括号,例如:

      2+3*5-4*(5-3)的逆波兰式为:
      235*+453-*-

后缀表达式在编程计算中有很大作用,我们通常需要将人类好处理的中缀表达式转化为计算机好处理的后缀表达式。

二、中缀表达式转后缀表达式

中缀表达式转后缀表达式是栈的一类应用,以下通过栈实现转化。

1、过程详解

例如   中缀表达式 a+b*c+(d*e+f)*g
       后缀表达式 abc*+de*f+g*+

依次遍历整个中缀表达式:

字符 'a' 输出;栈为空,所以把运算符 '+' 直接入栈;字符 'b' 输出:

 运算符 '*' 优先级高于栈顶,直接入栈;字符 'c' 输出:

 运算符 '+' 优先级低于栈顶,将 '*'、'+' 出栈且输出,再将 '+' 入栈:

左括号'('直接入栈,字符 'd'直接输出:

 操作符 '*' 直接入栈,字符'e' 直接输出:

操作符 '+' 优先级低于栈顶元素,栈顶元素'*'出栈且输出,随后 '+' 直接入栈;字符 'f' 直接输出:

遍历到右括号 ')' ,依次出栈且输出直到 '(' 出栈:

 运算符 '*' 优先级高于栈顶,直接入栈;字符 'g' 输出:

遍历完毕,将栈内元素依次输出:

 完整输出即为后缀表达式。

2、核心算法

利用一个符号栈实现,栈内储存运算符与括号。对于后缀表达式的部分直接output。

从左到右遍历中缀表达式的每个数字和符号

若是数字:输出,即成为后缀表达式的一部分;

若是符号:则判断其是否为括号。

             ▲若是括号:

                 左括号 —— 直接入栈

                 右括号 —— 不入栈,将栈顶元素依次出栈且输出

                                     直到遇见左括号,将左括号出栈

             ▲不是括号,即为运算符

                栈为空:入栈

                优先级比栈顶:入栈 

                其他情况:依次出栈且输出

                                  直到其优先级比栈顶,入栈         

遍历完中缀表达式后

将栈内剩余元素依次出栈、输出。

特别注意:

若运算符涉及到乘方 '^', 则上述算法过程中红色标注的“高”均要改为“高或等于”

否则a^b^c后缀表达式将会被错误输出为:ab^c^。错误的点在于,没有考虑到乘方运算符是左结合的。

3、代码实现

符号栈的结构:

typedef struct stack {
    int top;
    char array[200];
} *STACK, stack;

判断是否为括号: 

int IsParentheses(char c) {
    if (c == '(' || c == ')')
        return 1;
    return 0;
}

 判断是否为操作数:

在正确输入下,只要不是运算符和括号均为操作数。

int IsNumber(char c) {
    if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^')
        return 0;
    if (IsParentheses(c))
        return 0;
    return 1;
}

获取操作符优先级别:

方便起见,认为对操作符优先级规定一个数,数字越大优先级越高。 

int OpScore(char op) {
    if (op == '+' || op == '-')
        return 1;
    if (op == '*' || op == '/')
        return 2;
    if (op == '^')
        return 3;
}

比较两个运算符优先级:

前者比后者高则返回1,反之返回0。 

注意:当相等的情况下如果为乘方,则仍返回1。原因见上面算法分析里的特别注意。

int IsHigherOp(char op1, char op2) {
    if (OpScore(op1) > OpScore(op2))
        return 1;
    if (OpScore(op1) == OpScore(op2)) {
        if (OpScore(op1) == 3)
            return 1;
        else
            return 0;
    }
    return 0;
}

 完整代码

//
// Created by LittleCat on 2019/11/11.
//

#include <stdio.h>
#include <stdlib.h>

#define MAX 200

typedef struct stack {
    int top;
    char array[200];
} *STACK, stack;

int IsParentheses(char c) {
    if (c == '(' || c == ')')
        return 1;
    return 0;
}

int IsNumber(char c) {
    if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^')
        return 0;
    if (IsParentheses(c))
        return 0;
    return 1;
}

int OpScore(char op) {
    if (op == '+' || op == '-')
        return 1;
    if (op == '*' || op == '/')
        return 2;
    if (op == '^')
        return 3;
}

int IsHigherOp(char op1, char op2) {
    if (OpScore(op1) > OpScore(op2))
        return 1;
    if (OpScore(op1) == OpScore(op2)) {
        if (OpScore(op1) == 3)
            return 1;
        else
            return 0;
    }
    return 0;
}

int main() {
    int T;
    scanf("%d\n", &T);
    while (T--) {

        //创建初始符号栈
        STACK op = (STACK) malloc(sizeof(stack));
        op->top = 0;

        while(1) {
            char c = getchar();
            //判断输入是否结束
            if (c == '#') {
                while(op->top) {
                    putchar(op->array[op->top]);
                    op->top--;
                }
                printf("\n");
                break;
            }
            //此项为操作数,直接输出
            if (IsNumber(c))
                putchar(c);
            //此项为括号
            else if (IsParentheses(c)) {
                //左括号,入符号栈
                if (c == '(') {
                    op->array[++op->top] = c;
                }
                //右括号,依次输出直到'('
                else {
                    while (op->array[op->top] != '(') {
                        putchar(op->array[op->top]);
                        op->top--;
                    }
                    //'('出栈
                    op->top--;
                }
            }
            //此项为操作符
            else {
                h:
                //操作栈为空或栈顶为'(',入栈
                if (!op->top || op->array[op->top] == '(') {
                    op->array[++op->top] = c;
                }
                    //比栈顶元素优先级高,入栈
                else if (IsHigherOp(c, op->array[op->top])) {
                    op->array[++op->top] = c;
                } else {
                    //出栈
                    putchar(op->array[op->top--]);
                    goto h;
                }
            }
        }
        getchar();
        free(op);
    }
}


End

欢迎关注个人公众号“鸡翅编程”,这里是认真且乖巧的码农一枚,旨在用心写好每一篇文章,平常会把笔记汇总成推送更新~

发布了30 篇原创文章 · 获赞 16 · 访问量 1743

猜你喜欢

转载自blog.csdn.net/weixin_43787043/article/details/103939370