LinkedList 双端队列实现
面试官问:"LinkedList 除了是链表,还支持什么功能?"
候选人小方答:"呃... 队列?"
面试官追问:"那 ArrayDeque 和 LinkedList 有什么区别?分别在什么场景下用?"
小方答不上来。
【面试官心理】 这道题考查的是候选人对 LinkedList 实现的理解深度。LinkedList 不仅是 List,还是 Deque(双端队列),理解它的双重身份,才能在开发中正确选型。
一、LinkedList 的双重身份 🔴
1.1 类定义
1.2 Node 节点结构
二、双端队列操作 🔴
2.1 头部操作
2.2 尾部操作
2.3 操作复杂度
三、作为 List 使用 🟡
3.1 按索引访问
3.1 LinkedList vs ArrayList 按索引访问
四、作为 Queue/Deque 使用 🔴
4.1 Queue 方法
4.2 Deque 方法
4.3 栈操作
五、LinkedList vs ArrayDeque 🟡
5.1 核心区别
5.2 选型决策
5.3 性能测试对比
六、常见误区 ⚠️
❌ 误区一:LinkedList 插入一定比 ArrayList 快
错误:对于尾插,ArrayList 因为缓存友好的原因反而更快。
正确:LinkedList 只在头部插入/删除时有优势。
❌ 误区二:LinkedList 可以当作 Stack 用
正确但不推荐:LinkedList 可以当栈用,但 ArrayDeque 性能更好。
❌ 误区三:LinkedList 内存占用小
错误:LinkedList 的每个节点需要额外的指针存储,比 ArrayList 更耗内存。
七、面试官追问 🔴
面试官:"LinkedList 的迭代器是怎么实现的?"
标准回答:
listIterator(int index)返回ListItrListItr内部记录当前节点引用- 删除当前节点时调用
unlink(curr),只需要 O(1)
面试官追问:"为什么 ArrayDeque 的头尾操作是 O(1)?"
标准回答:
- ArrayDeque 是环形数组
- 头指针
head和尾指针tail可以循环移动 head = (head - 1) & (capacity - 1)实现环绕
面试官追问:"LinkedList 为什么用双向链表而不是单向链表?"
标准回答:
- 可以 O(1) 删除任意节点(已知前驱)
- 单向链表删除需要 O(n) 找到前驱
removeLast()可以直接拿到尾节点的前驱