优先级队列--合并多个有序链表

如果本文章有不懂的,请进入预习链接:优先级队列_加瓦不加班的博客-CSDN博客

优先级队列--合并多个有序链表_第1张图片

这道题目之前解答过,现在用刚学的优先级队列来实现一下

题目中要从小到大排列,因此选择用小顶堆来实现,自定义小顶堆如下

//小顶堆的操作与大顶堆的操作基本相似  但是我们这里就没有实现E,我们直接利用Node的val来实现
public class MinHeap {

    /*
              min
        1->4->5->null
        1->3->4->null
        2->6->null

        小顶堆
            1 2 4
        新链表
            s->1
     */
    ListNode[] array;
    int size;

    public MinHeap(int capacity) {
        array = new ListNode[capacity];
    }

    public void offer(ListNode offered) {
        int child = size++;
        int parent = (child - 1) / 2;
        while (child > 0 && offered.val < array[parent].val) {
            array[child] = array[parent];
            child = parent;
            parent = (child - 1) / 2;
        }
        array[child] = offered;
    }

    public ListNode poll() {
        if (isEmpty()) {
            return null;
        }
        swap(0, size - 1);
        size--;
        ListNode e = array[size];
        array[size] = null; // help GC

        down(0);

        return e;
    }

    private void down(int parent) {
        int left = 2 * parent + 1;
        int right = left + 1;
        int min = parent;
        if (left < size && array[left].val < array[min].val) {
            min = left;
        }
        if (right < size && array[right].val < array[min].val) {
            min = right;
        }
        if (min != parent) {
            swap(min, parent);
            down(min);
        }
    }

    private void swap(int i, int j) {
        ListNode t = array[i];
        array[i] = array[j];
        array[j] = t;
    }

    public boolean isEmpty() {
        return size == 0;
    }
}

代码:

public class E01Leetcode23 {
    public ListNode mergeKLists(ListNode[] lists) {
        // 1. 使用 jdk 的优先级队列实现
//        PriorityQueue queue = new PriorityQueue<>(Comparator.comparingInt(a -> a.val));
        // 2. 使用自定义小顶堆实现
        MinHeap queue = new MinHeap(lists.length);
        //将链表加入到小顶堆
        for (ListNode head : lists) {
            //注意:当List传入的是空
            if (head != null) {
                queue.offer(head);
            }
        }
        //新链表创建哨节点
        ListNode s = new ListNode(-1, null);
        ListNode p = s;
        //不断从堆顶移除最小元素,加入新链表
        while (!queue.isEmpty()) {
            ListNode node = queue.poll();
            p.next = node;
            p = node;
            if (node.next != null) {
                queue.offer(node.next);
            }
        }
        return s.next;
    }
}

测试用例:

//用例测试
public static void main(String[] args) {
    ListNode[] lists = {
            ListNode.of(1, 4, 5),
            ListNode.of(1, 3, 4),
            ListNode.of(2, 6),
            null,
    };
    ListNode m = new E01LetCode23().mergeKLists(lists);
    System.out.println(m);
}

提问:

  • 能否将每个链表的所有元素全部加入堆,再一个个从堆顶移除?

回答:

  • 可以是可以,但对空间占用就高了,堆的一个优点就是用有限的空间做事情

你可能感兴趣的:(链表,数据结构,算法)