栈的主要知识
目录
- 一、核心操作特点(仅暴露 “两端” 中的一端)
- 二、结构特点(逻辑结构 vs 物理实现)
- 三、应用场景特点(适合 “回溯”“临时缓存” 场景)
- 总结
- 四、栈的算法题
- 1.匹配括号
- 2.反转字符串
栈(Stack)是一种基础的数据结构,核心特点可以概括为 “先进后出(LIFO,Last-In-First-Out)”,就像日常生活中 “叠盘子”—— 最后叠上去的盘子,会被最先拿下来。其具体特点可从操作、结构、应用场景三方面展开:
一、核心操作特点(仅暴露 “两端” 中的一端)
栈的操作严格限制在 “栈顶”(即最后加入元素的位置),不允许直接操作栈中间或栈底的元素,常用操作只有 3 类,逻辑简单且可控:
- 入栈(Push):将元素添加到栈顶,栈的大小(元素个数)加 1;
例:栈中已有[a, b]
(b
是栈顶),入栈c
后,栈变为[a, b, c]
(c
成为新栈顶)。 - 出栈(Pop):从栈顶移除并返回元素,栈的大小减 1;
例:对[a, b, c]
出栈,会先移除c
,栈变为[a, b]
,返回值为c
。 - 查看栈顶(Peek):仅返回栈顶元素,不修改栈的结构(大小不变);
例:对[a, b, c]
执行peek
,返回c
,栈仍为[a, b, c]
。
此外,还会有辅助操作:isEmpty()
(判断栈是否为空)、size()
(获取栈中元素个数)。
二、结构特点(逻辑结构 vs 物理实现)
-
逻辑结构简单:本质是 “线性表” 的特殊形式(元素之间一对一相邻),但操作被严格限制(仅栈顶可操作),避免了无序访问的复杂度。
-
物理实现灵活 :
- 可用 数组 实现(顺序栈):栈底固定在数组下标 0,栈顶通过 “栈顶指针”(记录当前栈顶元素的下标)管理,操作高效(入栈 / 出栈时间复杂度
O(1)
)。 - 可用 链表 实现(链式栈):栈顶对应链表的头节点,入栈时新节点成为新头,出栈时移除头节点,同样无需移动元素,效率与顺序栈一致。
- 可用 数组 实现(顺序栈):栈底固定在数组下标 0,栈顶通过 “栈顶指针”(记录当前栈顶元素的下标)管理,操作高效(入栈 / 出栈时间复杂度
三、应用场景特点(适合 “回溯”“临时缓存” 场景)
正因为 “先进后出” 和 “仅栈顶操作” 的特点,栈特别适合需要 “记录历史步骤、回溯到上一步” 或 “临时存储待处理元素” 的场景,例如:
- 括号匹配(如你之前写的括号有效性判断):左括号入栈,遇到右括号时出栈匹配,未匹配完的左括号留在栈中。
- 字符串反转(如你用栈实现的
reverse2
方法):字符依次入栈,出栈时自然倒序。 - 函数调用栈(Java、C 等语言的底层机制):调用函数时,当前函数状态入栈;函数执行完,从栈顶恢复上一层函数状态,确保程序能回到调用前的位置继续执行。
- 表达式求值(如计算
3 + (2 * 4)
):用栈存储运算符和操作数,按优先级处理,确保先算括号内的表达式。
总结
栈的核心是 “先进后出 + 仅栈顶操作”,结构简单、操作可控,虽功能有限,但在需要 “回溯”“临时缓存” 的场景中效率极高,是编程中最基础且常用的数据结构之一。
四、栈的算法题
1.匹配括号
package 栈;import java.util.HashMap;
import java.util.Stack;public class Demo01 {public static void main(String[] args) {System.out.println(isValid("(){}[]]")); // 输出:false(最后多了一个])System.out.println(isValid("(){}[]")); // 输出:true(完全匹配)System.out.println(isValid("(]")); // 输出:false(类型不匹配)System.out.println(isValid("(()")); // 输出:false(左括号未匹配)}public static boolean isValid(String str) {HashMap<Character, Character> hashMap = new HashMap<>();hashMap.put(')', '(');hashMap.put('}', '{');hashMap.put(']', '[');Stack<Character> stack = new Stack<>();for (int i = 0; i < str.length(); i++) {char c = str.charAt(i);if (hashMap.containsKey(c)) {// 处理右括号:先判断栈是否为空if (stack.isEmpty()) {return false; // 栈空却有右括号,直接无效}// 弹出栈顶元素并判断是否匹配Character top = stack.pop();if (top != hashMap.get(c)) {return false; // 类型不匹配,返回无效}} else {// 左括号入栈stack.push(c);}}// 所有字符处理完后,栈必须为空才表示完全匹配return stack.isEmpty();}
}
2.反转字符串
package 栈;import java.util.Stack;//反转字符串
public class Two {public static void main(String[] args) {// 测试两种反转方法String string1 = reverse1("ab cdwfg");String string2 = reverse2("ab cdwfg");System.out.println(string1);System.out.println(string2);}// 利用StringBuilder反转字符串public static String reverse1(String str) {StringBuilder stringBuilder = new StringBuilder();// 从字符串末尾遍历到开头,逐个添加字符for (int i = str.length() - 1; i >= 0; i--) {char c = str.charAt(i); // 获取当前索引位置的字符stringBuilder.append(c); // 追加到StringBuilder}return stringBuilder.toString(); // 转换为字符串返回}// 利用栈的先进后出特性反转字符串public static String reverse2(String str) {Stack<Character> stack = new Stack<>(); // 用于存储字符的栈StringBuilder stringBuilder = new StringBuilder();// 将所有字符按顺序入栈for (int i = 0; i < str.length(); i++) {char c = str.charAt(i);stack.push(c); // 入栈}int size = stack.size(); // 记录栈的初始大小// 依次出栈并拼接(栈顶元素为原字符串最后一个字符)for (int i = 0; i < size; i++) {Character c = stack.pop(); // 出栈stringBuilder.append(c); // 追加到结果}return stringBuilder.toString(); // 返回反转后的字符串}
}```