栈动画演示
只在同一端进出,最后放进去的最先出来。
键盘:← → 单步 ·空格 播放/暂停 · R 重置 ·Home/End 到两端
栈只承认一个事实:最后压进去的最先弹出来。这一步到位的性质让它成为「撤销」「返回」「回溯」的共用底座——凡是「先进去的得等后面全部处理完才轮得到」的问题,都可以用它来记账。这一页把三种典型用法分开画:基础压弹看结构本身,括号匹配看它怎么配对,调用栈看函数返回地址存在哪儿。
括号匹配最能体现栈的价值:扫描时把左括号压进去,遇到右括号只跟栈顶比一次。因为最靠近右括号的那个左括号必须最先闭合,比栈顶以外的任何元素都有道理。失败也分三种各有各的说法:右括号多了、类型错配、扫描结束还有左括号没闭合,舞台末步会指名道姓地说是哪个下标出的问题。
栈演示怎么用
- 换模式:模式条里选基础压弹、括号匹配或调用栈。三种共用同一个竖排栈,栈顶固定在上方,格子上的 sub 写它排在第几层。
- 挑括号样例:切到括号匹配后,下拉里给了一段全配对的、一段类型错配的、一段少右括号的,还有一串右括号多余的,逐个看失败原因。
- 自己填串:选「自定义」然后在数据栏写一串括号,非括号字符会被跳过,这样能把表达式里的圆方花括号混着试。
- 看计数:入栈与出栈两个数字一路累加,空栈弹栈单独计数——它出现一次,就说明这一页把越界那条分支也走给你看了。
常见问题
为什么括号匹配非要用栈,用一个计数器不行吗?
只有圆括号时计数器够用,三种括号混在一起就必须记住「最近还没闭合的是哪一种」,这正是栈顶的含义。计数器丢掉的是类型信息,判断不了 ) 能不能闭合 [。
调用栈和普通栈有什么额外的事要做?
每层栈帧除了函数名还要存返回地址与局部变量,所以弹栈不只是删一个元素,而是把控制权交回上一层。页面上栈帧的 sub 标注了它是第几层,深度就是递归的最坏内存开销。
栈溢出到底溢出的是什么?
定长数组实现里 top 越过了数组边界;递归实现里是调用栈把预留的栈段用完。两者都是「压进去的层数超过了容器」,跟括号有没有配对无关。