编程自学指南:java程序设计开发,Java Stack 栈详解,理解栈的核心特性(LIFO),掌握 Stack 的 5 大核心方法,区分 Stack 与 Deque

编程自学指南:java程序设计开发,Java Stack 栈详解课件(初学者版)

一、课程信息

学习目标

  1. 理解栈的核心特性(LIFO)与生活场景
  2. 掌握 Stack 的 5 大核心方法(push/pop/peek/empty/search)
  3. 能通过栈解决实际问题(括号匹配、撤销操作)
  4. 区分 Stack 与 Deque 的使用场景,避免误用

二、课程导入:生活中的栈

🌰 生活案例:弹夹与盘子

  • 弹夹:最后压入的子弹最先射出(LIFO)
  • 餐厅叠盘:最后放的盘子最先被拿走
  • 书包书本:后塞的书先被取出

💻 代码场景:撤销操作

// 模拟文本编辑器的撤销(Undo)功能
Stack<String> undoStack = new Stack<>();
undoStack.push("插入'Hello'");
undoStack.push("删除最后一个字符");
// 撤销:执行 undoStack.pop() 回到上一步

📌 核心特性:后进先出(Last In First Out)

三、Stack 基础:核心方法与案例

1. 继承关系与初始化

import java.util.Stack;

Stack<String> stack = new Stack<>(); // 继承自Vector,线程安全(但推荐用Deque)

2. 五大核心方法(带案例)

方法名作用案例(以字符串栈为例)注意事项
push(E e)压栈(顶部添加元素)stack.push("A");返回压入的元素
pop()弹栈(移除并返回顶部元素)String top = stack.pop();空栈调用抛EmptyStackException
peek()查看顶部元素(不弹出)String peek = stack.peek();空栈调用抛EmptyStackException
empty()判断栈是否为空if (stack.empty()) {...}
search(E e)查找元素位置(顶部为 1)int pos = stack.search("B");不存在返回 - 1

3. 基础操作案例

Stack<Integer> nums = new Stack<>();
nums.push(10);  // 栈:[10]
nums.push(20);  // 栈:[10, 20]
System.out.println(nums.pop()); // 20(栈:[10])
System.out.println(nums.peek()); // 10(栈不变)
System.out.println(nums.search(10)); // 1(顶部元素位置)

四、栈的典型应用场景

案例 1:括号匹配(经典算法)

需求:判断字符串中括号是否匹配("()[]{}"
思路:遇到左括号压栈,遇到右括号弹栈并检查是否匹配

public static boolean isValid(String s) {
    Stack<Character> stack = new Stack<>();
    for (char c : s.toCharArray()) {
        if (c == '(' || c == '[' || c == '{') {
            stack.push(c);
        } else {
            if (stack.empty()) return false; // 右括号多余
            char top = stack.pop();
            if ((c == ')' && top != '(') ||
                (c == ']' && top != '[') ||
                (c == '}' && top != '{')) {
                return false; // 括号不匹配
            }
        }
    }
    return stack.empty(); // 左括号不能多余
}

// 测试:
System.out.println(isValid("()[]{}")); // true
System.out.println(isValid("([)]"));   // false

案例 2:逆序字符串

需求:将 "abc" 逆序为 "cba"
思路:压栈后依次弹出

public static String reverse(String str) {
    Stack<Character> stack = new Stack<>();
    for (char c : str.toCharArray()) {
        stack.push(c);
    }
    StringBuilder reversed = new StringBuilder();
    while (!stack.empty()) {
        reversed.append(stack.pop());
    }
    return reversed.toString();
}

// 输出:reverse("hello") → "olleh"

案例 3:浏览器历史记录(Undo/Redo)

需求:模拟浏览器的前进 / 后退
实现:两个栈(后退栈 + 前进栈)

Stack<String> backStack = new Stack<>();
Stack<String> forwardStack = new Stack<>();

// 访问页面A→B→C
backStack.push("A");
backStack.push("B");
backStack.push("C");

// 点击后退到B
String current = backStack.pop(); // C
forwardStack.push(current); // 前进栈存C
current = backStack.peek(); // B

// 点击前进到C
current = forwardStack.pop(); // C
backStack.push(current);

五、Stack vs Deque:选择与避坑

1. 核心区别

特性Stack(旧)Deque(推荐)
继承继承 Vector,线程安全接口,实现类(如 ArrayDeque)
方法push/pop/peek(专属)addFirst/removeFirst 等
线程安全是(但性能低)否(需手动同步)
推荐场景教学演示实际开发(替代 Stack)

2. 推荐写法:用 Deque 实现栈

Deque<String> stack = new ArrayDeque<>(); // 更高效
stack.push("A");   // 等价 addFirst()
stack.pop();       // 等价 removeFirst()

3. 初学者误区

  • 误区 1:认为 Stack 是唯一栈实现(实际 Deque 更优)
  • 误区 2:忽略空栈检查(pop()/peek()前先用empty()
  • 误区 3:在多线程中直接使用 Stack(应优先用ConcurrentLinkedDeque

六、内存分配与性能

1. 栈的内存模型(对比堆)

Stack<Integer> stack = new Stack<>(); // 栈引用在栈区,对象在堆区
stack.push(10); // 10是Integer对象,存储在堆区

图解:栈变量存堆地址,元素是堆中的对象(与数据结构的 “栈” 无关)。

2. 性能测试:压栈 10 万次

// Stack(旧)
long start = System.currentTimeMillis();
Stack<Integer> s = new Stack<>();
for (int i=0; i<100000; i++) s.push(i);
System.out.println("Stack耗时:" + (System.currentTimeMillis()-start)); // 约12ms

// Deque(推荐)
start = System.currentTimeMillis();
Deque<Integer> d = new ArrayDeque<>();
for (int i=0; i<100000; i++) d.push(i);
System.out.println("Deque耗时:" + (System.currentTimeMillis()-start)); // 约3ms

七、课堂练习

练习 1:简易计算器(后缀表达式)

需求:计算 "3 4 +" → 7(用栈实现)
提示:数字压栈,遇到运算符弹栈计算

Stack<Integer> nums = new Stack<>();
String[] tokens = "3 4 +".split(" ");
for (String token : tokens) {
    if (isNumber(token)) {
        nums.push(Integer.parseInt(token));
    } else {
        int b = nums.pop();
        int a = nums.pop();
        nums.push(calculate(a, b, token));
    }
}
System.out.println(nums.pop()); // 7

练习 2:有效括号扩展(含嵌套)

输入"{[()()]}"
输出true
提示:嵌套括号需严格匹配(用栈记录左括号)

八、课程总结

知识图谱:

栈 → LIFO特性 → push压栈,pop弹栈  
   ↳ 典型应用:括号匹配、逆序、撤销  
   ↳ 推荐写法:Deque替代Stack(高效)  
   ↳ 避坑:空栈检查、线程安全  

口诀记忆:

“栈似弹夹后入先出,push 压 pop 弹要记牢,
括号匹配栈来帮忙,Deque 替代性能强!”

九、课后作业(必做 + 选做)

必做 1:用栈实现十进制转二进制

输入:10
输出:1010
提示:除 2 取余,结果逆序(栈天然逆序)

必做 2:括号匹配升级(含多种括号)

输入"({[]})[()]"
输出true

选做:汉诺塔问题(递归 + 栈模拟)

需求:用栈模拟汉诺塔移动过程(提示:三个栈代表三根柱子)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zl515035644

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值