持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 28 天,点击查看活动详情 简单来说,所有需要后进先出的场景都可以考虑使用栈数据结构。那么后进先出的场景有哪些呢?给大家举几个例子。
比如十进制转二进制、判断字符串中的括号是否有效以及函数调用堆栈,这其实都是后进先出的场景。
大家看到这儿可能就会说了,这三个场景跟后进先出有什么关系,怎么感觉一点关系都没有呢?其实这三个场景都是典型的后进先出场景,给大家详细解读一下。
**场景一: **十进制转二进制。大家还记得我们上大学时候,学过的十进制转二进制的算法吗?这里简单回忆一遍,对于 35 这样一个十进制数字来说,如果你想把它转为二进制,那么你需要这样来操作:首先对 35 需要先除上一个 2,得到 17 余 1 并把它的余数记录下来;接着对 17 除上 2 得 8 余 1 也是记录下来;一直除到最后,把所有的余数都记录下来之后,倒序输出,得到的就是二进制数,最后得到结果是 100011。
我们可以发现这样一个规律,这个后出来的余数反而要排到前面。比如最后出来的这个余数 1,反而是二进制的第 1 个数字。这一个后一个前是不是就是后进先出呢?既然有后进先出这样的规律,那么我们就可以使用栈这个数据结构来实现这个算法。
我们把余数依次的入栈,然后再依次的出栈,由于栈它的后进先出这样一个特性,那么我们不就实现了这个余数的倒序输出吗?
**场景二: **有效的括号。这个什么意思呢?比如给你一个字符串,这些字符串都是一些括号这样的字符,让你判断字符串里面的括号是否是有效的,这个有效指的是它可以有效的闭合或者匹配。对于我们程序员来说,我们的代码里包含了大量的括号,比如小括号、花括号、中括号都有。如果括号没有正确的被闭合或者匹配,那么我们的编辑器通常都会报错。我们这个算法其实就是编辑器里面判断括号是否有效闭合或者匹配的算法。其实这个算法跟我们日常工作还是蛮接近的。
那么这样一个看似复杂的算法,为什么它是后进先出的呢?为什么可以用栈来解决呢?给大家解释一下。
仔细观察,其实我们可以发现这样一个规律,对于那些还没有闭合的左括号而言,比如上图第一个括号字符串,这些越靠后的左括号,它对应的右括号就越靠前。那么这一个后一个前是不是又让大家想到了这个后进先出呢?
那么我们是不是就可以用栈这个数据结构来解决这个问题呢?左括号想象成入栈的操作。右括号想象成出栈的操作,就可以满足刚才所说的这个后进先出了。
具体怎么做呢?我们从左到右遍历这个字符串,遇到左括号就入栈,遇到右括号就出战。如果最后栈空了,说明这个字符串就是合法的。
利用图中的四个例子里面验证这个算法逻辑。第一个操作,依次入栈了 6 个左括号,此时栈里面有 6 个左括号,接着依次一次遇到了对应的闭合的右括号,就执行了 6 次出战的操作。最后栈是空的,所以说它是合法的。
第二个操作,比如先入栈一个左括号,遇到右括号出栈,此时栈是空的,接着又入栈一个左括号,又遇到右括号出栈,此时栈为空的,依次执行完也是空的,所以这个也是合法的。
第三个操作,依次入栈 8个左括号,最后就出栈了一个左括号,此时栈不为空,说明是不合法的。
第四个操作,这个操作看起来还挺复杂的,首先它入栈了 3 个左括号,遇到一个右括号,出栈一个左括号,剩余 2 个左括号,接着又入栈 2 左括号,此时栈中有 4 个左括号,依次遇到 4 个右括号,最后所有的左括号出栈,栈为空,最后一个也是合法的。
到这里,证明我们的这个算法是没有问题的。有效的括号问题可以用栈这个数据结构来解决。