1. 栈与队列的核心概念解析
栈和队列作为最基础的两种线性数据结构,在Java开发中扮演着算法基石的角色。虽然它们都基于数组或链表实现,但操作特性却截然不同。
1.1 栈的FILO特性实战
栈遵循后进先出(LIFO)原则,就像我们日常叠放的盘子——最后放上去的总是最先被取用。在Java中,Stack类虽然存在但已不推荐使用,更建议用Deque接口的实现类替代:
java复制Deque<Integer> stack = new ArrayDeque<>();
stack.push(1); // 入栈
stack.push(2);
int top = stack.pop(); // 出栈,返回2
实际开发中,栈常用于:
- 方法调用时的栈帧管理(JVM虚拟机栈)
- 括号匹配校验(LeetCode经典题型)
- 撤销操作的历史记录存储
关键技巧:使用ArrayDeque而非LinkedList实现栈,在频繁push/pop操作时性能提升30%以上
1.2 队列的FIFO特性实现
队列遵循先进先出(FIFO)原则,就像排队买票——先来的人先获得服务。Java中的Queue接口有多种实现:
java复制Queue<String> queue = new LinkedList<>();
queue.offer("A"); // 入队
queue.offer("B");
String first = queue.poll(); // 出队,返回"A"
循环队列是解决假溢出问题的经典方案,核心是通过取模运算实现指针循环:
java复制rear = (rear + 1) % capacity;
front = (front + 1) % capacity;
1.3 双端队列的灵活运用
Deque(双端队列)融合了栈和队列的特性,允许在两端进行操作。ArrayDeque是其高性能实现:
java复制Deque<Character> deque = new ArrayDeque<>();
deque.addFirst('a'); // 前端插入
deque.addLast('z'); // 后端插入
char first = deque.removeFirst(); // 前端删除
2. 优先级队列的实战应用
PriorityQueue基于堆结构实现,元素按照自然顺序或Comparator定义的顺序出队:
java复制PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.offer(3);
pq.offer(1);
pq.offer(2);
while(!pq.isEmpty()) {
System.out.println(pq.poll()); // 输出1,2,3
}
性能注意点:
- 插入操作时间复杂度O(log n)
- 查询最小元素O(1)
- 底层是最小堆实现
3. 二叉树基础与Java实现
3.1 二叉树核心概念
二叉树每个节点最多有两个子节点,分为:
- 满二叉树:所有非叶子节点都有两个子节点
- 完全二叉树:除最后一层外全满,最后一层左对齐
- 二叉搜索树:左子树值 < 根值 < 右子树值
3.2 二叉树的链式存储
Java实现节点结构:
java复制class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
3.3 遍历算法实现
递归实现前序遍历:
java复制void preOrder(TreeNode root) {
if(root == null) return;
System.out.println(root.val); // 先访问根
preOrder(root.left);
preOrder(root.right);
}
迭代实现中序遍历(使用栈):
java复制List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
while(root != null || !stack.isEmpty()) {
while(root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
res.add(root.val);
root = root.right;
}
return res;
}
4. 常见问题排查手册
4.1 栈溢出问题
递归深度过大导致StackOverflowError的解决方案:
- 改用迭代算法
- 增加JVM栈空间:-Xss2m
- 尾递归优化(Java暂不支持)
4.2 队列阻塞处理
使用LinkedBlockingQueue时的死锁预防:
- 设置合理的capacity
- 使用offer(e, timeout)替代put()
- 配置拒绝策略
4.3 二叉树遍历陷阱
中序遍历BST时的常见错误:
java复制// 错误写法:会修改遍历中的树结构
while(root != null) {
stack.push(root);
root = root.left; // 此处修改了root引用
}
// 正确做法应保留原始引用
TreeNode current = root;
5. 性能优化实战建议
-
栈选择原则:
- 单线程环境:ArrayDeque
- 多线程环境:ConcurrentLinkedDeque
- 固定容量:自己实现数组栈
-
队列选型指南:
- 高吞吐:LinkedBlockingQueue
- 延迟任务:DelayQueue
- 无锁实现:ConcurrentLinkedQueue
-
二叉树优化技巧:
- 频繁查询:AVL树保持平衡
- 大量插入:红黑树减少旋转
- 范围查询:B+树优化磁盘IO
对于树结构的线程安全问题,推荐使用CopyOnWriteArrayList实现的安全迭代器模式,虽然会增加内存开销,但能保证遍历过程中的结构稳定性。
