数据结构与算法之 leetcode 队列合并 K 个链表算法 优先队列

数据结构与算法阿木 发布于 2025-07-12 9 次阅读


队列合并 K 个链表算法(优先队列)实现分析

在数据结构与算法的学习过程中,链表和队列是两个非常重要的概念。而将这两个概念结合起来,解决实际问题,如合并 K 个链表,则是一个典型的应用场景。本文将围绕“队列合并 K 个链表算法”这一主题,结合优先队列的使用,进行详细的分析和代码实现。

合并 K 个链表是一个常见的面试题,它要求我们将 K 个链表按照某种顺序合并成一个链表。这个顺序可以是升序、降序或者根据链表节点的某个属性进行排序。在解决这类问题时,优先队列(也称为最小堆或最大堆)是一个非常有用的数据结构。

链表与队列简介

链表

链表是一种线性数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表具有以下特点:

- 链表中的节点在内存中可以不连续。

- 链表插入和删除操作的时间复杂度为 O(1)。

- 链表不支持随机访问。

队列

队列是一种先进先出(FIFO)的数据结构,它支持以下操作:

- 入队(enqueue):在队列尾部添加一个元素。

- 出队(dequeue):从队列头部移除一个元素。

- 队列长度:获取队列中元素的数量。

优先队列

优先队列是一种特殊的队列,它支持以下操作:

- 插入(offer):将元素插入队列。

- 移除(poll):移除并返回队列头部元素。

- 元素比较:根据元素的大小关系进行排序。

在 Java 中,可以使用 `PriorityQueue` 类来实现优先队列。`PriorityQueue` 默认是一个最小堆,即队列头部元素总是最小的。

队列合并 K 个链表算法

算法思路

1. 创建一个优先队列,用于存储 K 个链表的头部节点。

2. 遍历每个链表,将每个链表的头部节点插入优先队列。

3. 循环执行以下操作,直到优先队列为空:

- 从优先队列中移除头部元素,将其添加到结果链表中。

- 如果移除的节点有下一个节点,将其插入优先队列。

4. 返回结果链表。

代码实现

以下是一个使用 Java 实现的队列合并 K 个链表的示例代码:

java

import java.util.PriorityQueue;

class ListNode {


int val;


ListNode next;


ListNode(int x) { val = x; }


}

public class MergeKLists {


public ListNode mergeKLists(ListNode[] lists) {


if (lists == null || lists.length == 0) {


return null;


}



PriorityQueue<ListNode> queue = new PriorityQueue<>((a, b) -> a.val - b.val);



// 将每个链表的头部节点插入优先队列


for (ListNode list : lists) {


if (list != null) {


queue.offer(list);


}


}



ListNode dummy = new ListNode(0);


ListNode current = dummy;



// 循环处理优先队列


while (!queue.isEmpty()) {


ListNode node = queue.poll();


current.next = node;


current = current.next;



// 如果移除的节点有下一个节点,将其插入优先队列


if (node.next != null) {


queue.offer(node.next);


}


}



return dummy.next;


}


}


算法分析

- 时间复杂度:O(NlogK),其中 N 是所有链表节点总数,K 是链表数量。每次从优先队列中移除和插入元素的时间复杂度为 O(logK),总共需要处理 N 个节点。

- 空间复杂度:O(K),优先队列中最多存储 K 个节点。

总结

本文介绍了队列合并 K 个链表算法,并详细分析了算法思路和代码实现。通过使用优先队列,我们可以高效地合并 K 个链表,并保持链表元素的顺序。在实际应用中,我们可以根据具体需求调整优先队列的比较器,以实现不同的排序方式。