数据结构:栈的应用—后缀表达式的运算、中缀表达式转后缀表达式


categories:

  • 数据结构

后缀(逆波兰)表达式

中缀表达式:就是我们平时用的标准四则运算表达式,运算符在操作数中间,例如:9+(3-1)*3+10/2

后缀表达式:也称为逆波兰表达式,是将运算符写在操作数之后的表达式,例如上式的后缀表达式为:9 3 1 - 3 * + 10 2 / +

作用:对计算机而言,中缀表达式是比较复杂的结构,而逆波兰式在计算机看来却是比较简单易懂的结构。因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序

计算机如何用后缀表达式求值

例如:中缀表达式 9+(3-1)*3+10/2 的后缀表达式 9 3 1 - 3 * + 10 2 / +,计算机如何用该后缀表达式进行运算呢

规则:从左到右遍历后缀表达式的每个数字和符号,遇到数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果

详细过程如下9 3 1 - 3 * + 10 2 / +

  1. 初始化一个空栈,该栈用来对要运算的数字进出使用
  2. 后缀表达式中前三个都是数字,所以9 3 1依次进栈,如下图
    在这里插入图片描述
  3. 接下来是 - 运算符,所以将栈顶的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再将2进栈,如下图左侧
  4. 接着是数字3进栈,如下图右侧
    在这里插入图片描述
  5. 接下来是* ,也就意味着栈中3与2出栈,相乘得到6,再将6入栈,如下图左侧
  6. 再下来是+ ,将6与9出栈,相加得到15,再将15入栈,如下图右侧
    在这里插入图片描述
  7. 接着是10与2两数字进栈,如下图左侧
  8. 接下来是/ ,因此栈顶的2与10出栈,10与2相除得到5,5入栈,如下图右侧
    在这里插入图片描述
  9. 最后是运算符+ ,所以5与15出栈相加得到20,再将20进栈,如下图左侧
  10. 后缀表达式遍历结束,最后栈中结果是20出栈,栈变为空,计算结束,如下图右侧
    在这里插入图片描述

以上可以看出后缀表达式可以很顺利地解决计算问题,因此后缀表达式是很重要的,接下来就要知道常用的中缀表达式如何转换为后缀表达式

中缀表达式转后缀表达式

:中缀表达式 9+(3-1)*3+10/2 转换为后缀表达式 9 3 1 - 3 * + 10 2 / +

规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止,总结如下:
在这里插入图片描述

详细过程如下9+(3-1)*3+10/2 转换为后缀表达式 9 3 1 - 3 * + 10 2 / +

  1. 初始化一空栈,用来对符号进出栈使用,如下图左侧

  2. 第一个是数字9,直接输出,后面是符号+,进栈,如下图右侧在这里插入图片描述

  3. 第三个字符是(,左括号还未配对,入栈,如下图左侧

  4. 第四个字符是数字3,直接输出,总表达式为9 3,接着是-,进栈,如下图右侧在这里插入图片描述

  5. 接下来是数字1,输出,总表达式为9 3 1,后面是),此时,要去匹配之前的左括号,所以栈顶依次输出,直到(出栈。总的表达式现在为9 3 1 -,栈中剩下+,如下图左侧

  6. 紧接着是*,因为此时栈顶为+号,优先级低于乘号,因此不输出,乘号进栈,接着是数字3,输出,总表达式为9 3 1 - 3,如下图右侧在这里插入图片描述

  7. 之后是+,此时栈顶为乘号,栈顶优先级高,因此栈中元素出栈并输出(没有比+更低的优先级,所以全部出栈),总输出表达式9 3 1 - 3 * +。然后将当前这个符号+进栈,如下图左侧

  8. 紧接着是数字10,直接输出,总表达式变为9 3 1 - 3 * + 10。然后是/ ,栈顶+优先级低于除号,/进栈,如下图右侧在这里插入图片描述

  9. 接下来是最后一个数字2,输出,表达式为9 3 1 - 3 * +10 2,如下图左侧

  10. 中缀表达式遍历结束,将栈中符号依次全部出栈并输出,最后输出的后缀表达式为:9 3 1 - 3 * +10 2 / + 在这里插入图片描述

C代码如下

//中缀表达式转后缀表达式
//中缀表达式存储在字符串中,为便于表示,代码使用9+(3-1)*3+8/2为例子

#include "stack.h"
#include <stdio.h>

int main()
{
    Stack s;
    InitStack(&s);

    const char mid[] = "9+(3-1)*3+8/2";  //中缀表达式
    char back[14];  //后缀表达式
    int i = 0;
    int j = 0;
    char useless;

    for (i = 0; i < 13; i++)
    {
        if (mid[i] <= '9'&&mid[i] >= '0')  //是数字,直接输出
        {
            back[j] = mid[i];
            j++;
        }
        else if (mid[i] == '(')  //是左括号,直接入栈
        {
            Push(&s, mid[i]);
        }
        else if (mid[i] == ')')  //是右括号,栈中出栈直到第一个左括号出栈
        {
            while (GetTop(&s) != '(')
            {
                Pop(&s, &back[j]);
                j++;
            }
            Pop(&s, &useless);            
        }
        else if (mid[i] == '*' || mid[i] == '/')  //是*/,出栈,直到栈空或者栈中遇到左括号或+-,当前符号入栈
        {
            while (!IsEmpty(&s) && (GetTop(&s) != '+' && GetTop(&s) != '-'))
            {
                Pop(&s, &back[j]);
                j++;
            }
            Push(&s, mid[i]);
        }
        else if (mid[i] == '+' || mid[i] == '-')  //是+-,出栈,直到栈空或者左括号当前符号入栈
        {
            while (!IsEmpty(&s)&&GetTop(&s) != '(')
            {
                Pop(&s, &back[j]);
                j++;
            }
            Push(&s, mid[i]);
        }
    }
    //中缀表达式遍历结束,要将栈中剩余符号依次弹出
    while (!IsEmpty(&s))
    {
        Pop(&s, &back[j]);
        j++;
    }
    back[j] = '\0';

    printf("中缀表达式: %s\n\n", mid);
    printf("后缀表达式: %s\n\n", back);

    return 0;
}

代码运行结果:
在这里插入图片描述

综上,要想让计算机拥有处理我们通常的标准(中缀)表达式的能力,最重要的是两大步

  • 将中缀表达式转换为后缀表达式(栈用来进出运算的符号)

  • 将后缀表达式进行运算得到结果(栈用来进出运算的数字)

  • 上述过程充分利用了栈的后进先出特性,是栈这种数据结构比较重要的应用*

全部评论

相关推荐

头像
11-09 12:17
清华大学 C++
out11Man:小丑罢了,不用理会
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务