数据结构之队列和栈的应用

本文介绍队列和栈的实际应用:括号匹配、表达式求值

数据结构之队列和栈的应用


一、括号匹配问题

【问题描述】:给定一个仅含有括号的字符串,如何去判断该括号序列是否合法呢?
例如:()()合法,(())合法,【()】合法
但((()不合法,【)【)不合法

用栈来解决。

数据结构之队列和栈的应用
下面开始模拟算法,走两遍


比如第一种情况:【()】【】

参考上面的算法思想,执行过程:
1、先看第一个括号,因为是左括号,所以直接把第一个括号【,压入栈中。
2、再看第二个,也是左括号(,所以直接扔进栈就行
3、第三个括号是右括号),所以我们要弹出一个栈顶元素 ( 进行匹配,发现两者正好匹配,然后继续。现在栈中就只有一个元素【了。
4、第四个括号是】,同上,因为是右括号,所以弹出栈顶元素,然后发现是匹配的。继续,现在栈中没有元素了。
5、第五个是左括号,入栈
6、第六个是右括号,同三,匹配。现在栈中又没有元素了
7、字符串读取完毕,且此时栈中为空,所以字符串是满足括号匹配的!


情况2、字符串:【()

执行过程:
1、第一个括号为左括号,直接入栈
2、第二个括号为左括号,直接入栈
3、第三个括号为),弹出栈顶元素(,并检查是否匹配,发现两者匹配,因此继续。现在栈中元素为【
4、字符串读取完毕,但栈不空,所以该括号字符串不满足括号匹配!


情况3、字符串:【(】【】

执行过程:
1、第一个括号为左括号,直接入栈
2、第二个括号为左括号,直接入栈
3、第三个括号为右括号,所以弹出栈顶元素(,检查发现(和】是不匹配的,因此算法直接return false。该字符串不匹配。


二、表达式求值

先介绍三种表达式:
数据结构之队列和栈的应用
那么复杂的表达式,如何完成中缀转前缀呢?

中缀转前缀

核心思想,比如(A+B)*C
我们先把括号内部优先级高的,A+B转成前缀:+AB
然后把(+AB) *C种的+AB看作一个数
因此,最后的转换结果是:
*+ABC

数据结构之队列和栈的应用


中缀转后缀

数据结构之队列和栈的应用
思路和转前缀一样


用栈实现的算法模拟:

我们以中缀转后缀为例子

数据结构之队列和栈的应用

执行过程:
1、检测到是左括号(,入栈
2、同上,左括号入栈
3、检测到是数字A,于是将其抄写下来,此时后缀表达式为:A
4、运算符+,根据规则c,运算符优先级是高于左括号的,直接入栈
5、然后检测到数字B,于是抄写下来,此时后缀表达式为:AB
6、遇到右括号了,注意规则b,我们将栈中的运算符全部弹出加入到表达式中,然后直到遇到左括号,将其删除。此时后缀表达式为:AB+。栈中此时为:(
7、遇到*,乘号优先级比括号高,直接压到栈里面。
8、遇到数字C,将其抄写下,此时后缀表达式为:AB+C
9、遇到右括号,将乘号弹出,此时后缀表达式为:AB+C*。并且根据规则b,还要将栈中的左括号删除。那么此时栈中就空了
10、遇到-,因为栈空,直接入栈,
11、遇到左括号,加入栈中
12、遇到数字E,抄写下来,此时后缀表达式为:AB+C*E
13、遇到减号-,因为栈顶是(,所以直接入栈,此时栈内为:- ( -
三个元素
14、遇到数字F,抄写,此时后缀表达式为:AB+C * EF
15、遇到右括号,将减号弹出,加入到表达式中,并且把左括号删除
此时后缀表达式为 AB+C * EF-
16、根据规则d,遍历完成,将栈中所有元素弹出,加入到表达式里。于是弹出减号,此时后缀表达式为 AB+C * EF–

得到最后的答案。

这个算法手动模拟起来稍微麻烦一点,大家多试试,弄熟就好了


后缀表达式求值

那么我们幸幸苦苦学会了中缀表达式转后缀表达式,到底是为了什么呢?相信很多读者看到这里都会有这样的疑问。哈哈,其实就是因为用后缀表达式来求值是一件非常简单的事情!而中缀表达式交给计算机去直接算,那可就麻烦了。

因此,我们回了中缀转后缀之后,就可以将复杂的中缀表达式先转成后缀表达式,然后再用后缀表达式的求值算法来计算出最后的值。

那,说了这么多,后缀表达式求值到底有多简单呢?

算法思想
利用一个栈,每次把操作数扔进栈,遇到一个运算符就把栈顶两个元素弹出做一个运算,然后再把运算结果压到栈中,循环以上过程,最后在栈里会得到一个数字,就是结果。

说的有点抽象,来个例子:
比如我们以上面那个后缀表达式为例子:
AB+C*EF–
比如我们取A = 3;B = 2;C = 2;E = 6;F = 4
那么根据其对应的中缀表达式【(A + B) * C】 - 【E - F】
我们可以算出,结果为8
下面我们用后缀表达式算法检验一下:

1、遇到数,无脑扔进栈。所以AB直接扔进,现在栈中元素:AB
2、遇到+,于是将栈顶两个元素AB弹出,做运算A+B = 3 + 2 = 5,将结果5压入栈
3、遇到C,直接入栈
4、遇到*,于是将C、5弹出,做运算C*5 = 5 * 2 = 10;将10压入栈
5、遇到E、F,直接无脑入栈,那么现在栈中:10, E, F三个元素
6、遇到-,将E、F弹出,做运算E - F = 6 - 4 = 2;将2压入栈
7、遇到-,将10、2弹出,做运算10 - 2 = 8。
8、字符串遍历完毕,栈中仅有的是结果,所以结果为8,经检验,算法正确!


所以今后做表达式求值算法的思路就很明确了,先将中缀表达式转后缀,然后再用后缀表达式求值算法求出结果即可。人比较擅长中缀表达式求值,但计算机更喜欢后缀表达式运算