Java栈与队列深度解析:结构、实现与应用指南

一、栈与队列核心概念对比

特性 栈 (Stack) 队列 (Queue)
数据原则 LIFO(后进先出) FIFO(先进先出)
核心操作 push(入栈)、pop(出栈)、peek(查看栈顶) offer(入队)、poll(出队)、peek(查看队首)
典型应用 函数调用栈、括号匹配、撤销操作 任务调度、BFS算法、消息缓冲队列
Java实现类 Stack (遗留类) / Deque LinkedList / ArrayDeque / PriorityQueue

二、栈的Java实现方案

1. 标准库实现

java 复制代码
// 推荐使用Deque作为栈(Java官方建议)
Deque<Integer> stack = new ArrayDeque<>();

// 基本操作
stack.push(10);          // 入栈
int top = stack.peek();  // 查看栈顶(不删除)
int val = stack.pop();   // 出栈

// 不推荐使用遗留Stack类(同步开销大)
Stack<String> legacyStack = new Stack<>();

2. 自定义数组栈实现

java 复制代码
public class ArrayStack<E> {
    private static final int DEFAULT_CAPACITY = 10;
    private Object[] elements;
    private int top = -1;

    public ArrayStack() {
        this(DEFAULT_CAPACITY);
    }

    public ArrayStack(int capacity) {
        elements = new Object[capacity];
    }

    public void push(E item) {
        if (top == elements.length - 1) {
            resize();
        }
        elements[++top] = item;
    }

    public E pop() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        E item = (E) elements[top];
        elements[top--] = null; // 帮助GC
        return item;
    }

    private void resize() {
        int newSize = elements.length * 2;
        elements = Arrays.copyOf(elements, newSize);
    }
}

三、队列的Java实现体系

1. 队列类型与实现类

队列类型 特点 实现类
普通队列 先进先出,无优先级 LinkedList / ArrayDeque
优先队列 按优先级出队 PriorityQueue
阻塞队列 支持等待式操作 ArrayBlockingQueue / LinkedBlockingQueue
双端队列 两端都可操作 ArrayDeque / LinkedList
并发队列 线程安全 ConcurrentLinkedQueue

2. 队列操作对比

java 复制代码
Queue<String> queue = new LinkedList<>();

// 添加元素
queue.offer("A");     // 推荐(返回boolean)
queue.add("B");       // 可能抛异常

// 移除元素
String head = queue.poll();  // 返回null为空
String elem = queue.remove(); // 空队列抛异常

// 查看队首
String peek = queue.peek();  // 不删除元素

四、核心数据结构实现原理

1. 栈的链表实现

java 复制代码
public class LinkedStack<E> {
    private static class Node<E> {
        E item;
        Node<E> next;
        Node(E item, Node<E> next) {
            this.item = item;
            this.next = next;
        }
    }

    private Node<E> top;
    private int size;

    public void push(E item) {
        top = new Node<>(item, top);
        size++;
    }

    public E pop() {
        if (top == null) throw new EmptyStackException();
        E item = top.item;
        top = top.next;
        size--;
        return item;
    }
}

2. 循环队列实现(解决假溢出)

java 复制代码
public class CircularQueue<E> {
    private final Object[] elements;
    private int front; // 队首指针
    private int rear;  // 队尾指针
    private int count; // 元素计数

    public CircularQueue(int capacity) {
        elements = new Object[capacity];
    }

    public boolean offer(E e) {
        if (count == elements.length) return false;
        elements[rear] = e;
        rear = (rear + 1) % elements.length;
        count++;
        return true;
    }

    public E poll() {
        if (count == 0) return null;
        E e = (E) elements[front];
        elements[front] = null;
        front = (front + 1) % elements.length;
        count--;
        return e;
    }
}

五、高级应用场景

1. 栈的应用:括号匹配检查

java 复制代码
public static boolean isBalanced(String expression) {
    Deque<Character> stack = new ArrayDeque<>();
    for (char c : expression.toCharArray()) {
        if (c == '(' || c == '[' || c == '{') {
            stack.push(c);
        } else {
            if (stack.isEmpty()) return false;
            char top = stack.pop();
            if ((c == ')' && top != '(') ||
                (c == ']' && top != '[') ||
                (c == '}' && top != '{')) {
                return false;
            }
        }
    }
    return stack.isEmpty();
}

2. 队列的应用:生产者-消费者模型

java 复制代码
BlockingQueue<Task> queue = new LinkedBlockingQueue<>(10);

// 生产者线程
new Thread(() -> {
    while (true) {
        Task task = generateTask();
        try {
            queue.put(task); // 阻塞直到有空间
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}).start();

// 消费者线程
new Thread(() -> {
    while (true) {
        try {
            Task task = queue.take(); // 阻塞直到有元素
            processTask(task);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}).start();

六、性能对比与选型建议

1. 不同实现的性能对比

操作 ArrayDeque LinkedList PriorityQueue
插入/删除 O(1) O(1) O(log n)
随机访问 O(1) O(n) O(n)
内存占用 连续空间更优 节点额外开销 数组堆结构

2. 选型决策树

复制代码
是否需要优先级处理?
├── 是 → 使用PriorityQueue
└── 否 → 需要线程安全?
           ├── 是 → 使用ConcurrentLinkedQueue或BlockingQueue
           └── 否 → 预估数据量?
                       ├── 小 → LinkedList
                       └── 大 → ArrayDeque

七、常见问题解决方案

1. 实现最小栈(O(1)获取最小值)

java 复制代码
class MinStack {
    private Deque<Integer> stack = new ArrayDeque<>();
    private Deque<Integer> minStack = new ArrayDeque<>();

    public void push(int x) {
        stack.push(x);
        if (minStack.isEmpty() || x <= minStack.peek()) {
            minStack.push(x);
        }
    }

    public void pop() {
        if (stack.pop().equals(minStack.peek())) {
            minStack.pop();
        }
    }

    public int getMin() {
        return minStack.peek();
    }
}

2. 用队列实现栈

java 复制代码
class MyStack {
    Queue<Integer> queue = new LinkedList<>();

    public void push(int x) {
        queue.offer(x);
        // 将前n-1个元素重新入队
        for (int i = 1; i < queue.size(); i++) {
            queue.offer(queue.poll());
        }
    }

    public int pop() {
        return queue.poll();
    }
}

八、Java 8+新特性应用

1. Stream操作队列

java 复制代码
Queue<Integer> queue = new LinkedList<>(Arrays.asList(3,1,4,1,5));

// 过滤并收集
List<Integer> filtered = queue.stream()
                             .filter(n -> n > 2)
                             .collect(Collectors.toList());

// 并行处理(注意线程安全)
ConcurrentLinkedQueue<Integer> safeQueue = new ConcurrentLinkedQueue<>(queue);
safeQueue.parallelStream()
         .map(n -> n * 2)
         .forEach(System.out::println);

2. Lambda表达式简化操作

java 复制代码
PriorityQueue<String> pq = new PriorityQueue<>(
    (a, b) -> b.length() - a.length() // 自定义比较器
);

pq.offer("Java");
pq.offer("Python");
pq.offer("C++");

while (!pq.isEmpty()) {
    System.out.println(pq.poll()); 
    // 输出:Python, Java, C++
}

九、最佳实践总结

  1. 栈的选择原则

    • 单线程环境优先使用ArrayDeque

    • 需要同步时使用Collections.synchronizedDeque()

    • 避免使用遗留的Stack

  2. 队列的选择原则

    • 高并发场景使用ConcurrentLinkedQueue

    • 需要阻塞功能选择BlockingQueue实现

    • 优先级处理使用PriorityQueue

  3. 通用建议

    • 预估数据规模选择底层存储结构

    • 注意边界条件(空栈/空队列操作)

    • 合理使用容量限制防止内存溢出

性能口诀

  • 数组实现随机访问快

  • 链表实现增删效率高

  • 优先队列按需排序

  • 并发场景选择线程安全实现

通过深入理解栈和队列的特性,开发者可以更高效地解决算法问题和系统设计挑战。

相关推荐
Katherine_lin2 分钟前
JAVA:线程的状态与生命周期
java·开发语言
钮钴禄·爱因斯晨22 分钟前
深入理解 Java 内存区域与内存溢出异常
java·开发语言
uhakadotcom22 分钟前
BentoML远程代码执行漏洞(CVE-2025-27520)详解与防护指南
后端·算法·面试
_x_w25 分钟前
【16】数据结构之基于树的排序算法篇章
开发语言·数据结构·python·算法·链表·排序算法
北辰浮光33 分钟前
[SpringMVC]上手案例
java·开发语言
西门吹雪分身39 分钟前
Redis之RedLock算法以及底层原理
数据库·redis·算法
九转苍翎40 分钟前
Java虚拟机——JVM(Java Virtual Machine)解析二
java·jvm
顾林海1 小时前
深度解析LinkedHashMap工作原理
android·java·面试
一路向北he1 小时前
杰理10k3950温度测量
java·数据结构·算法
K哥11251 小时前
【多线程】线程池
java·开发语言·线程池