【Java教程】Day9-13 集合:栈(Stack)数据结构

栈(Stack)是一种后进先出(LIFO,Last In First Out)数据结构,意味着最后进栈的元素最先被弹出。栈是一种非常简单但功能强大的数据结构,广泛应用于程序的函数调用栈、表达式计算、深度优先搜索(DFS)等场景。

 

1. 栈的基本操作

1.1 栈有三个基本操作:

  • 压栈(Push):将元素压入栈顶。

  • 弹栈(Pop):从栈顶弹出元素。

  • 查看栈顶元素(Peek):返回栈顶元素,但不移除它。

 

1.2 LIFO vs FIFO

为了理解栈的工作原理,我们首先回顾一下队列(Queue)的特点。队列遵循先进先出(FIFO,First In First Out)原则,即最先进入队列的元素最早出队列。而栈遵循后进先出(LIFO)原则,即最后进入栈的元素最早弹出。

以下是一个简化的视觉对比:

1.2.1 队列(FIFO):

less入队列:  A -> B -> C -> D出队列:  A <- B <- C <- D

 

1.2.2 栈(LIFO):

less入栈:  A -> B -> C -> D出栈:  D <- C <- B <- A

 

1.3 Java 中的栈实现

在 Java 中,可以使用 Deque 接口来模拟栈的功能。Deque(双端队列)是一个可以在两端进行操作的数据结构,我们可以利用它来实现栈的操作。虽然 Java 提供了一个遗留类 Stack 来表示栈,但不推荐使用它,因其过时且功能不如 Deque 灵活。

2. Deque 实现栈操作

Deque 接口提供了多种方法来进行栈的操作,我们可以利用以下方法来实现栈的功能:

  • 压栈addFirst(E e) 或 offerFirst(E e)

  • 弹栈removeFirst() 或 pollFirst()

  • 查看栈顶元素getFirst() 或 peekFirst()

示例代码:使用 Deque 实现栈

javaimport java.util.Deque;import java.util.LinkedList;public class StackDemo {    public static void main(String[] args) {        Deque<String> stack = new LinkedList<>();                // 压栈        stack.addFirst("A");        stack.addFirst("B");        stack.addFirst("C");                // 查看栈顶元素        System.out.println("栈顶元素: " + stack.peekFirst());  // 输出: C                // 弹栈        System.out.println("弹出栈顶元素: " + stack.removeFirst());  // 输出: C        System.out.println("弹出栈顶元素: " + stack.removeFirst());  // 输出: B                // 查看栈顶元素        System.out.println("栈顶元素: " + stack.peekFirst());  // 输出: A    }}

 

在这个例子中,使用 LinkedList 来实现 Deque 接口,并通过 addFirst() 方法压栈,removeFirst() 方法弹栈,peekFirst() 方法查看栈顶元素。

3. 为什么不推荐使用遗留类 Stack

尽管 Java 早期提供了 Stack 类,它继承自 Vector,并且具有 push()pop(), 和 peek() 等方法,但 Stack 类并没有现代 Deque 接口的多功能性,且其性能和灵活性较差。因此,推荐使用 Deque 来实现栈的功能。

4. 栈的应用

栈在计算机科学中有广泛的应用。以下是一些常见的使用场景:

4.1  方法调用栈

当一个程序执行时,每当一个方法被调用时,JVM 会将该方法的执行状态压入栈中。当方法执行完毕后,它会从栈中弹出,返回调用者。栈的这种行为使得程序能够正确地进行方法的调用与返回。

例如,在执行以下递归函数时,JVM 会使用栈来维护每个递归调用的状态:


 
javapublic class Main {    public static void main(String[] args) {        increase(1);    }    static int increase(int x) {        return increase(x) + 1;  // 无限递归    }}

 

如果递归调用太深,会导致栈溢出,抛出 StackOverflowError 错误。

4.2 十进制转十六进制

栈在进制转换中的应用也非常常见。举个例子,我们可以用栈来将一个整数转换为十六进制。以下是具体步骤:

  • 将数字除以 16,获取余数,并将余数压栈。

  • 重复上述操作,直到商为 0。

  • 从栈中弹出所有元素,形成最终的十六进制字符串。


 

 

javaimport java.util.*;public class StackHexConversion {    public static void main(String[] args) {        int number = 12500;        String hex = toHex(number);        System.out.println("十六进制表示: " + hex);  // 输出: 30D4    }    static String toHex(int n) {        if (n == 0) return "0";                Deque<Character> stack = new LinkedList<>();        String hexChars = "0123456789ABCDEF";        while (n > 0) {            stack.push(hexChars.charAt(n % 16));            n /= 16;        }                StringBuilder result = new StringBuilder();        while (!stack.isEmpty()) {            result.append(stack.pop());        }                return result.toString();    }}

 

4.3 计算后缀表达式

后缀表达式(逆波兰表示法)是计算表达式的一种方式,可以通过栈来计算。下面是计算后缀表达式 1 2 9 5 - * + 的示例:


 

 

javaimport java.util.*;public class SuffixExpressionCalculator {    public static void main(String[] args) {        String expression = "1 2 9 5 - * +";        System.out.println("结果: " + calculateSuffixExpression(expression));  // 输出: 9    }    static int calculateSuffixExpression(String exp) {        Deque<Integer> stack = new LinkedList<>();        String[] tokens = exp.split(" ");                for (String token : tokens) {            if (isOperator(token)) {                int b = stack.pop();                int a = stack.pop();                int result = applyOperator(a, b, token);                stack.push(result);            } else {                stack.push(Integer.parseInt(token));            }        }                return stack.pop();    }    static boolean isOperator(String token) {        return token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/");    }    static int applyOperator(int a, int b, String operator) {        switch (operator) {            case "+": return a + b;            case "-": return a - b;            case "*": return a * b;            case "/": return a / b;            default: throw new IllegalArgumentException("Unknown operator " + operator);        }    }}

 

5. 小结

  • (Stack)是一种后进先出(LIFO)的数据结构,主要操作有压栈(push)、弹栈(pop)和查看栈顶元素(peek)。

  • 在 Java 中,可以使用 Deque 接口来实现栈,Deque 提供了与栈操作相对应的方法:addFirst()(压栈)、removeFirst()(弹栈)、peekFirst()(查看栈顶元素)。

  • 不建议使用过时的 Stack 类,推荐使用 Deque 实现栈功能。

  • 栈在方法调用管理、进制转换、后缀表达式计算等多种场景中都有广泛应用。

 

通过这些例子,你可以更好地理解栈的实现和应用,并在实际开发中灵活使用它。

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值