一、栈的基础知识
基础线性结构:链表,队列,栈
栈结构,先入后出(FILO);
从哪入从哪出,好比一个羽毛球桶,拿羽毛球时,最先拿外面的。
js中数组提供了push()和pop()方法,可以实现类似栈的行为。
基本操作:入栈(压入,增加数据)和出栈(弹出,删除数据)
从逻辑上讲,入栈就是栈顶指针向上移动一位(A4元素就算入栈了),出栈就是栈顶指针向下移动一位(A4元素就算出栈了); 如图所示
二、栈适合解决什么问题?
栈:可以处理具有完全包含关系的问题
- 处理表达式求值
- 处理递归程序
- 处理括号匹配
- 处理二叉树遍历
括号匹配
- 在任意一个位置上,左括号的数量 >= 右括号的数量
- 在最后一个位置上,左括号的数量 == 右括号的数量
- 程序中只需要记录左括号数量和右括号数量即可
实现(记录左括号数量L、右括号数量R)
思路 1. L >= R, 最终 L == R;
记录两个变量L、R, 遇到左括号L + 1, 遇到右括号R + 1; 最终L == R即可
思路 2. L - R >= 0, 最终L - R == 0;
可以定义一个L = 0, 遇到左括号 +1,遇到右括号- 1,最终等于0即可。
针对思路 2 分析:—— 栈
- 遇到左括号 +1:进栈
- 遇到右括号 -1:出栈
- 例如:"(()())",里面的括号必须先匹配完后,才能匹配到最外层的括号,所以说外层括号肯定是完全包含内里括号的。
栈的典型应用场景
1. 操作系统中的线程池
进程{ 线程池[线程1,线程2,线程3] }
线程:线程空间本质上就是栈;
线程空间可叫线程栈(是有空间大小的限制的)
爆栈:递归超出线程栈大小
多线程编程
2. 表达式求值
用递归解决与用基础栈结构解决表达式求值,在本质上没有任何差别,递归直接用系统栈,与自己在程序中实现一个栈解决是一样的
-
表达式树:以运算符作为根节点,相关的操作数作为子节点
-
如表达式:3 * (4 + 5),这是一个乘法表达式,4+5只是我们再算乘法之前需要解决的一个子问题
- 乘法包含子问题(完全包含关系)
- 之所以认为他是一个乘法表达式那是因为乘号是整个表达式中最后一个被计算的运算符;
- 这个最后被计算的运算符,本质上是表达式中运算符优先级最低的那个运算符