当前位置: 首页 > news >正文

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

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

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

二、栈的Java实现方案

1. 标准库实现

// 推荐使用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. 自定义数组栈实现

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. 队列操作对比

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. 栈的链表实现

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. 循环队列实现(解决假溢出)

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. 栈的应用:括号匹配检查

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. 队列的应用:生产者-消费者模型

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. 不同实现的性能对比

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

2. 选型决策树

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

七、常见问题解决方案

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

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. 用队列实现栈

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操作队列

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表达式简化操作

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. 通用建议

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

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

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

性能口诀

  • 数组实现随机访问快

  • 链表实现增删效率高

  • 优先队列按需排序

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

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

相关文章:

  • 用密钥方式让通过JumpServer代理的服务器可以在我本地电脑直接访问
  • Java 设计模式:外观模式详解
  • 5.6 GitHub PR分析爆款方案:分层提示工程+LangChain实战,准确率飙升22%
  • 什么是RAG
  • Nodejs Express框架
  • 【ai回答记录】在sql中使用DATE_SUB 跟 用python或者java的Date计算时间差,哪个速度更加快?
  • 214、【数组】下一个排列(Python)
  • 目标追踪数据标注
  • WITRAN_2DPSGMU_Encoder 类
  • Lombok库
  • 电子电器架构 --- 智能座舱的定义
  • [Linux]umask及其设置
  • 【prometheus+Grafana篇】Prometheus与Grafana:深入了解监控架构与数据可视化分析平台
  • 深度学习总结(12)
  • 10.第二阶段x64游戏实战-添加计时器
  • Mysql概述
  • MCP 认证考试常见技术难题实战分析与解决方案
  • Python(14)Python内置函数完全指南:从基础使用到高阶技巧
  • 爱普生EV7050EAN在ONT交换机的应用
  • GPT-SoVITS:5 步实现 AI 语音克隆
  • 俄方证实俄总统普京正在会见美特使威特科夫
  • 历史一刻,两个航天员乘组拍摄全家福
  • 大家聊中国式现代化|彭羽:为国家试制度探新路,推进高水平对外开放
  • 舞剧《百合花》7月绽放,王安忆:这是送给母亲的一份礼物
  • 蚌埠一动物园用染色犬扮熊猫引争议,园方回应:被投诉已撤走
  • 蔚来李斌:当下国际贸易环境有不确定性,但坚信中国汽车产业最终将占全球四成份额