【优先级队列】

基于无序数组实现

要点

  1. 入队保持顺序,在数组尾部插入即可
  2. 出队前找到优先级最高的出队,相当于一次选择排序

基于有序数组的实现

要点

  1. 入队后排好序,优先级最高的排列在尾部
  2. 出队只需删除尾部元素即可

基于堆的实现

堆是一种基于树的数据结构,通常用完全二叉树实现。堆的特性如下

  • 在大顶堆中,任意节点 C 与它的父节点 P 符合 P . v a l u e ≥ C . v a l u e P.value \geq C.value P.valueC.value
  • 而小顶堆中,任意节点 C 与它的父节点 P 符合 P . v a l u e ≤ C . v a l u e P.value \leq C.value P.valueC.value
  • 最顶层的节点(没有父亲)称之为 root 根节点

完全二叉树可以使用数组来表示:
在这里插入图片描述

特征

  • 如果从索引 0 开始存储节点数据
    • 节点 i i i 的父节点为 f l o o r ( ( i − 1 ) / 2 ) floor((i-1)/2) floor((i1)/2),当 i > 0 i>0 i>0
    • 节点 i i i 的左子节点为 2 i + 1 2i+1 2i+1,右子节点为 2 i + 2 2i+2 2i+2,当然它们得 < s i z e < size <size
  • 如果从索引 1 开始存储节点数据
    • 节点 i i i 的父节点为 f l o o r ( i / 2 ) floor(i/2) floor(i/2),当 i > 1 i > 1 i>1
    • 节点 i i i 的左子节点为 2 i 2i 2i,右子节点为 2 i + 1 2i+1 2i+1,同样得 < s i z e < size <size

用大顶锥实现优先级队列:
入队:将新元素加入队尾,然后不断比较其与父节点的优先级,若大于父节点优先级,则交换两节点,然后再比较新节点的父节点,直到找到小于父节点优先级,或者当前节点(child)索引为0,则找到。

public boolean offer(E offered) {
        if (isFull()) {
            return false;
        }
        int child = size++;//当前child指向数组最后一个元素,然后size++
        int parent = (child - 1) / 2;
        while (child > 0 && offered.priority() > array[parent].priority()) {
            array[child] = array[parent];
            child = parent;
            parent = (child - 1) / 2;
        }
        array[child] = offered;
        return true;
    }

出队:将数组索引为0的元素与数组最后元素交换,交换后数组最后一个元素就是优先级最大的元素,将其出队,然后将数组为0位置元素逐步下潜,调整大顶锥,使其满足大顶锥定义。


    public E poll() {
        if (isEmpty()) {
            return null;
        }
        swap(0, size - 1);
        size--;
        Priority e = array[size];
        array[size] = null;
        
        shiftDown(0);        
        return (E) e;
    }
    

    void shiftDown(int parent) {
        int left = 2 * parent + 1;
        int right = left + 1;
        int max = parent;
        if (left < size && array[left].priority() > array[max].priority()) {
            max = left;
        }
        if (right < size && array[right].priority() > array[max].priority()) {
            max = right;
        }
        if (max != parent) {
            swap(max, parent);
            shiftDown(max);
        }
    }
    private void swap(int i, int j) {
	        Priority t = array[i];
	        array[i] = array[j];
	        array[j] = t;
	}

合并多个有序链表-力扣 23 题

在这里插入图片描述

思路:小顶锥实现,k个链表创建有k个元素的小顶锥,用优先级队列实现(遍历lists,如果遍历到的不是空链表,将头节点加入到优先级队列中,)当队列不空时循环取出元素,取出的这个元素就是最小的元素,并将此元素加入到新的链表中,然后将当前这个最小的元素的next节点入队(当next节点存在的情况下),当优先级队列为空时表示已经将k个链表合并。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        Queue<ListNode> pq = new PriorityQueue<>((v1, v2)-> v1.val - v2.val);
        for(ListNode node : lists){
            if(node != null){
                pq.offer(node);
            }
        }
        ListNode sentinel = new ListNode(-1, null);
        ListNode tail = sentinel;
        while(!pq.isEmpty()){
            ListNode minNode = pq.poll();
            tail.next = minNode;
            tail = minNode;
            if(minNode.next != null){
                pq.offer(minNode.next);
            }
        }
        return sentinel.next;
    }

    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值