栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
栈
栈是一种特殊的线性表,智能在一端进行操作:
往栈中添加元素的操作,一般叫做 push,入栈;
从栈中移除元素的操作,一般叫做 pop,出栈(只能移除站定元素,也叫做:弹出栈顶元素);
后进先出的原则,Last In First Out ~ LIFO。
接口设计
|
|
因为动态数组和双向链表在添加删除随后一个元素的复杂度都是 O(1) 级别,所以这两种数据结构都可以用来实现栈。下面是采用动态数组实现的栈。
实现-继承
采用继承的方式实现栈,继承 ArrayList 实现:
clear()
、size()
和isEmpty()
父类已经实现了。
测试:
打印结果:
继承可以实现栈的效果,但是却存在一个问题:stack 可以访问到 ArrayList 所有的开放接口,stack.add()
、stack.remove()
等。解决方案👇。
实现-组合
采用组合的方式实现栈,实现:
测试:
打印结果:
应用
游览器的前进和后退就是通过栈来实现的:
依次访问 jd.com、qq.com 和 baidu.com:
后退
后退
前进
访问 taobao.com
类似场景:软件的撤销、恢复功能。
源码分析
Stack 继承自 Vector,Vector 也是动态数组,相较于 ArrayList,Vector 是线程安全的。
练习
有效的括号
- 遇见左字符,将左字符入栈;
- 遇见右字符:
如果展示空的,说明括号无效;
如果站不为空,将栈顶字符出出栈,与右字符匹配:
-> 如果左右字符不匹配 -> 括号无效;
-> 如果左右字符匹配 -> 继续扫描下一个字符; - 所有字符扫描完毕后:
栈为空 -> 括号有效;
栈不为空 -> 括号无效;12345678910111213141516171819public boolean isValid(String s) {Stack<Character> stack = new Stack<>();for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if (c == '(' || c == '[' || c == '{') {stack.push(c);} else {if (stack.isEmpty()) return false;char left = stack.pop();if (left == '(' && c != ')') return false;if (left == '[' && c != ']') return false;if (left == '{' && c != '}') return false;}}return stack.isEmpty();}
括号的分数
856. 括号的分数
括号的分数 - 方法二:栈
逆波兰表达式求值
逆波兰表达式
150. 逆波兰表达式求值
基本计算器
224. 基本计算器