【Java---数据结构】优先级队列 PriorityQueue(堆)

目录

一、二叉树的顺序存储

🍎存储方式

🍎下标的关系

二、堆(heap)

🍎概念

🍎堆的创建

 三、堆的应用 ---- 优先级队列(PriorityQueue)

🍎概念:

🍎PriorityQueue 的基本方法

🍎实现PriorityQueue 的基本方法

🛫入队

🛫出队

🛫获取队头元素

四、堆排序

五、TopK 问题

🚀TopK 问题练习:LeetCode -- 查找和最小的 K 对数字

六、PriorityQueue的比较方式

🍎方式一:实现 Comparable 接口

🍎方式二:实现 Comparator 接口。

🍎方式三:利用内部类实现(简写实现 Comparator接口的方法)


一、二叉树的顺序存储

🍎存储方式

  • 使用数组保存二叉树结构,方式即将二叉树用层序遍历方式放入数组中。
  • 一般只适合表示完全二叉树,因为非完全二叉树会有空间的浪费。
  • 这种方式的主要用法就是堆的表示。

🍎下标的关系

已知双亲(parent)的下标,则:

  • 左孩子(left)下标:   left = 2 * parent + 1;
  • 右孩子(right)下标: right = 2 * parent + 2;

已知孩子(不区分左右)(child)下标,则:

  • 双亲(parent)下标:parent = (child - 1) / 2

二、堆(heap)

🍎概念

  • 堆逻辑上是一棵完全二叉树
  • 堆物理上是保存在数组中
  • 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆,或者最大堆
  • 反之,则是小堆,或者小根堆,或者最小堆
  • 堆的基本作用是,快速找集合中的最值

🍎堆的创建

堆是由顺序表实现的,堆的本质就是一棵完全二叉树,且每棵子树双亲结点大于(或小于)孩子结点(大于就是大根堆,小于就是小根堆),可以根据这个特点创建堆。

🍓创建堆的过程:

  • 找到堆中最后一棵子树的双亲结点。对该子树进行向下调整。
  • 如果需要创建大根堆,则找到该子树两个子结点值较大的结点,然后与根结点进行比较。
  • 如果孩子结点比根结点大,则交换两个结点的值,然后在数组的大小范围内,对已交换结点的子树进行向下调整,直到被调整的子树下标超出数组的范围或满足大堆条件即停止调整。
  • 如果需要创建小根堆,则找到该树两个子结点值较小的结点,然后根结点进行比较。
  • 如果孩子结点比根结点小,则交换两结点的值,然后在数组的大小范围内,对已交换结点的子树进行向下调整调整,直到被调整的子树下标超出数组的范围或满足小堆条件即停止调整。
  • 设最后一棵子树的双亲结点所对应数组下标为parent,其左子树结点为child,数组大小为len,由于该树是一棵完全二叉树,所以下标满足 child = 2 ∗ parent + 1 ; parent = ( child − 1 ) / 2
  • 最后一个结点下标为 len − 1, 即最后一棵子树的父结点:parent =( (len-1) - 1 ) / 2(len-1 相当于 child )。

🍓向下调整的过程:

  • 大根堆:从最后一棵子树的父节点开始向上进行比较【 parent-- 遍历每一棵子树(parent每减一次,就指向前一棵子树的父结点)。】,如果一棵子树的右结点存在且大于左结点的值,则child++指向右结点,子节点与父结点进行比较,如果子节点大于父结点,就进行交换。
  • 小根堆:从根节点开始向下进行比较【 parent++ 遍每一棵子树(parent每加一次,就指向下一棵子树的父结点)。】如果一棵子树的右结点存在且小于左结点的值,则child++指向右结点,子节点与父结点进行比较,如果子节点小于父结点,就进行交换。

以创建大根堆为例

🌊代码示例

public class TreeHeap {
    public int[] elem;
    public int usedSize;
    public TreeHeap(){
        this.elem = new int[10];
    }

    /**
     * 交换结点的值
     * @param array 目标数组
     * @param index1 待交换结点的下标
     * @param index2 待交换结点的下标
     */
    public void swap(int[] array,int index1,int index2){
        int tmp = array[index1];
        array[index1] = array[index2];
        array[index2] = tmp;
    }

    /**
     * 向下调整
     * @param parent 每棵树的根节点
     * @param len 每棵树调整的结束位置
     */
    public void shiftDown(int parent,int len){
        int child = 2*parent+1;
        while (child<len){
            if(child+1<len && this.elem[child]<this.elem[child+1]){
                child++;
            }
            if(this.elem[child]>this.elem[parent]){
                swap(elem,child,parent);
                parent = child;
                child = 2*parent+1;
            }else {
                break;
            }
        }
    }

    /**
     * 创建大根堆
     * @param array 结点的值
     */
    public void createTreeHeap(int[] array){
        //拷贝数据
        for (int i = 0; i < array.length; i++) {
            elem[i] = array[i];
            usedSize++;
        }
        //从最后一棵子树的父结点开始调整
        for (int parent = (usedSize-1-1)/2; parent >=0  ; parent--) {
            shiftDown(parent,usedSize);
        }
    }

🍉时间复杂度分析

  • 最坏的情况:从根一路比较到叶子,比较的次数为完全二叉树的高度
  • 建堆的过程是自下而上的,堆的本质就是一棵完全二叉树,设该二叉树的高度为h,堆元素个数为n,建堆时需要对所有高度大于1的子树进行调整,最坏情况下该堆是一个满二叉树,设堆所在的层为n(n从1开始),即第n层的子树需要调整 h - n 次。

💦时间复杂度推导过程

 三、堆的应用 ---- 优先级队列(PriorityQueue)

🍎概念:

  • 在很多应用中,通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象。
  • 最简单的一个例子就是,在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话。
  • 有一种数据结构提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列。

优先级队列的实现方式有很多,但最常见的是使用堆来构建。在java中,优先队列(PriorityQueue类),默认是以小根堆实现。

🍎PriorityQueue 的基本方法

🌊代码示例

public class TestDemo {
    public static void main(String[] args) {
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();//创建一个优先级队列
        priorityQueue.offer(13);
        priorityQueue.offer(3);
        priorityQueue.offer(20);
        System.out.println(priorityQueue); //打印优先级队列
        System.out.println(priorityQueue.poll()); //弹出队头元素
        System.out.println(priorityQueue.peek()); //获取队头元素
    }
}

运行结果:
[3, 13, 20] //默认使用小根堆实现
3
13

🍎实现PriorityQueue 的基本方法

🛫入队

  • 将待入队的元素放入堆尾(二叉树的最后一个结点)。
  • 对堆尾的结点进行向上方向调整,因为入队一个元素后,堆中只有一条到新插入结点路径上不是大根堆,所以只需要对该结点进行向上调整即可。
  • 向上调整:比较调整结点与父亲结点值的大小。以大根堆为例,如果子结点值比父结点的值大,则与父亲结点的值进行交换,否则就不需要调整。
  • 因为交换后不知道上面的子树是否为大根堆,所以需要对交换路径上所有的结点进行向上调整,直到调整到根结点,如果在向上调整的过程中出现父亲结点比子节点的值大(该堆已满足大根堆条件),就结束调整。
  • 如果是小根堆,向上调整的结点与父亲结点的进行比较,如果子结点值比父结点的值小,则与父亲结点的值进行交换,否则就不需要调整。
  • 入队完成。

💦入队过程

 

🌊代码示例

import java.util.Arrays;

public class TreeHeap {
    public int[] elem;
    public int usedSize;
    public TreeHeap(){
        this.elem = new int[10];
    }

    /**
     * 交换结点的值
     * @param array 目标数组
     * @param index1 待交换结点的下标
     * @param index2 待交换结点的下标
     */
    public void swap(int[] array,int index1,int index2){
        int tmp = array[index1];
        array[index1] = array[index2];
        array[index2] = tmp;
    }

    /**
     * 向上调整
     * @param child 待调整结点的下标
     */
    public void shiftUp(int child){
        int parent = (child-1)/2;
        while (child>0){
            if(this.elem[child]>this.elem[parent]){
                swap(elem,child,parent);
                child = parent;
                parent = (child-1)/2;
            }else{
                break;
            }
        }
    }

    /**
     * 优先级队列 入队操作
     * @param val 待入队的元素
     */
    public void offer(int val){
        //如果满了就进行扩容
        if(isFull()){
            this.elem = Arrays.copyOf(elem,elem.length*2);
        }
        //在最后位置插入元素
        this.elem[usedSize++] = val;
        //传入数组最后一个元素
        shiftUp(usedSize-1);
    }

    /**
     * 判断队列是否满了
     * @return 如果满了就返回true,否则返回去false
     */
    public boolean isFull(){
        return this.usedSize == this.elem.length;
    }
}

🛫出队

每次出队列都要保证出最大的或最小的

  1. 将堆顶(二叉树的根节点)元素与堆尾(二叉树的最后一个结点)元素交换,保存并删除堆尾元素。
  2. 从根节点开始向下调整二叉树,调整为大根堆或小根堆。
  3. 返回之前保存的元素。

💦出队过程

🌊代码示例

public class TreeHeap {
    public int[] elem;
    public int usedSize;
    public TreeHeap(){
        this.elem = new int[10];
    }

    /**
     * 交换结点的值
     * @param array 目标数组
     * @param index1 待交换结点的下标
     * @param index2 待交换结点的下标
     */
    public void swap(int[] array,int index1,int index2){
        int tmp = array[index1];
        array[index1] = array[index2];
        array[index2] = tmp;
    }

    /**
     * 向下调整 (大根堆)
     * @param parent 每棵树的根节点
     * @param len 每棵树调整的结束位置
     */
    public void shiftDown(int parent,int len){
        int child = 2*parent+1;
        while (child<len){
            if(child+1<len && this.elem[child]<this.elem[child+1]){
                child++;
            }
            if(this.elem[child]>this.elem[parent]){
                swap(elem,child,parent);
                parent = child;
                child = 2*parent+1;
            }else {
                break;
            }
        }
    }

    /**
     * 优先级队列 出队操作
     * @return 返回出队列结点的值
     */
    public int poll(){
        //如果队列为空就抛出异常
        if(isEmpty()){
            throw new RuntimeException("优先级队列为空!");
        }
        swap(elem,0,usedSize-1);
        int ret = this.elem[usedSize-1]; //保存交换后的堆尾元素
        usedSize--; //交换后删除
        shiftDown(0,usedSize);
        return ret;
    }

    /**
     * 判断队列是否为空
     * @return 如果为空就返回true,否则返回false
     */
    public boolean isEmpty(){
        return usedSize == 0;
    }
}

🛫获取队头元素

优先级队列的队头元素就是数组0下标的元素,然后0下标的元素即可。

🌊代码示例

    public int peek(){
        if(isEmpty()){
            throw new RuntimeException("优先级队列为空!");
        }
        return this.elem[0];
    }

    /**
     * 判断队列是否为空
     * @return 如果为空就返回true,否则返回false
     */
    public boolean isEmpty(){
        return usedSize == 0;
    }

四、堆排序

如果是升序,则使用大堆,如果是降序,则使用小堆。

升序排序的步骤:

  • 将数组转换成大根堆。
  • 创建一个索引end标记最后一个元素。
  • 将堆顶元素与end标记的元素进行交换。
  • 交换完以后,从堆顶结点开始进行向下调整,调整的结点下标小于end。
  • 调整为大根堆以后,end--。
  • 重复上述步骤,直到 end < 0 ,停止。
  • 因为大根堆堆顶存放最大元素,所以每次将堆顶元素与end标记的元素进行交换,再调整end-1部分的堆,这样就能依次将大的元素放在后面。
  • 降序排列使用小根堆也是一样的,每次使用向上调整。

💦对下面这个数组进行升序排序

💦创建成大根堆

💦排序过程

💦排序后的数组

🌊代码示例

public class TreeHeap {
    public int[] elem;
    public int usedSize;
    public TreeHeap(){
        this.elem = new int[10];
    }

    /**
     * 交换结点的值
     * @param array 目标数组
     * @param index1 待交换结点的下标
     * @param index2 待交换结点的下标
     */
    public void swap(int[] array,int index1,int index2){
        int tmp = array[index1];
        array[index1] = array[index2];
        array[index2] = tmp;
    }

    /**
     * 向下调整
     * @param parent 每棵树的根节点
     * @param len 每棵树调整的结束位置
     */
    public void shiftDown(int parent,int len){
        int child = 2*parent+1;
        while (child<len){
            if(child+1<len && this.elem[child]<this.elem[child+1]){
                child++;
            }
            if(this.elem[child]>this.elem[parent]){
                swap(elem,child,parent);
                parent = child;
                child = 2*parent+1;
            }else {
                break;
            }
        }
    }

    /**
     * 创建大根堆
     * @param array 结点的值
     */
    public void createTreeHeap(int[] array){
        //拷贝数据
        for (int i = 0; i < array.length; i++) {
            elem[i] = array[i];
            usedSize++;
        }
        //从最后一棵子树开始调整
        for (int parent = (usedSize-1-1)/2; parent >=0  ; parent--) {
            shiftDown(parent,usedSize);
        }
    }

    /**
     * 堆排序(升序)
     */
    public void heapSort(){
        int end = this.usedSize-1;
        while(end>0){
           swap(this.elem,0,end);
            shiftDown(0,end);
            end--;
        }
    }
}

五、TopK 问题

topK问题:在大量的数据中找出最大或者最小的前k个元素,例如:在100万个数据中找到最大的10个数。(这些数据是无序的)

思路一:

  • 对所有数据进行排序,然后找到前K个最大或最小的元素。这种方式不推荐,因为只需要前K个最值元素,没有必要对所有数据进行排序,而且对整体数据进行排序最快的时间复杂度是:O(\large n*log_{2} n)。

思路二:

  • 使用堆。例如求前k个最大的元素,可以创建一个大根堆的优先队列,将所有数据入队,再出队K个元素,这K个元素就是前K个最大的元素。

思路三: topK问题的标准解决思路

  • 例如求前k个最大元素。先将数组前K个元素创建为小根堆。

为什么创建的是小根堆?

  • 因为小根堆中堆顶元素是最小的。那么这个大小为K的小根堆堆顶元素一定是当前K个元素中最小的一个元素。然后从数组第K+1个元素开始遍历剩下的元素,如果有元素比堆顶元素大,那么这个元素可能就是topK中的一个元素(可能是前K个最大的元素之一)。此时的堆顶元素一定不是前K个最大的元素。
  • 如果堆顶元素小于数组中的元素,那么出堆顶元素,入当前比堆顶大的元素,然后重新调整为小根堆。
  • 遍历完数组后,这个大小为K的小根堆中的元素就是前K个最大的元素。
  • 时间复杂度:O(\large n*log_{2}k),当K越来越小时,时间复杂度就是O(n)。
  • 同理找前K个最小的元素需要使用大根堆,思路与求前K个最大元素是一样的。

📔 总结:

  • 如果求前K个最大的元素,要创建一个小根堆。
  • 如果求前K个最小的元素,要创建一个大根堆。
  • 求第K大的元素。需要创建一个小根堆,堆顶元素就是第K大的元素。
  • 求第K小的元素。需要创建一个大根堆,堆顶元素就是第K小的元素。堆内元素就是前K个最小的元素。

🌊代码示例

import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;

public class Topk {
    /**
     * 前K个最小的元素(需要创建大根堆,堆的大小为K)
     * @param array
     * @param k
     * @return
     */
    public static int[] topk(int[] array,int k){
        //创建一个大小为k的大根堆
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        //遍历数组中的元素,将元素放入创建的堆中
        for(int i=0;i<array.length;i++){
            if(maxHeap.size()<k){
                maxHeap.offer(array[i]);
            }else{
                //从第k+1个元素开始,每个元素与堆顶元素进行比较
                int top = maxHeap.peek();
                if(top>array[i]){
                    maxHeap.poll();
                    maxHeap.offer(array[i]);
                }
            }
        }
        int[] ret = new int[k];
        for (int i = 0; i < k; i++) {
            ret[i] = maxHeap.poll();
        }
        return ret;
    }

    public static void main(String[] args) {
        int[] array = {18,21,8,10,34,12};
        int[] ret = topk(array,3);
        System.out.println(Arrays.toString(ret));
    }
}
运行结果:[12, 10, 8]

🚀TopK 问题练习:LeetCode -- 查找和最小的 K 对数字

📌题目描述

  • 给定两个以 升序排列 的整数数组 nums1 和 nums2 , 以及一个整数 k 。
  • 定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2 。
  • 请找到和最小的 k 个数对 (u1,v1),  (u2,v2)  ...  (uk,vk) 。

📋题目示例

  • 示例一:
输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
输出: [1,2],[1,4],[1,6]
解释: 返回序列中的前 3 对数:
     [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]
  • 示例二:
输入: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
输出: [1,1],[1,1]
解释: 返回序列中的前 2 对数:
     [1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]
  • 示例三:
输入: nums1 = [1,2], nums2 = [3], k = 3 
输出: [1,3],[2,3]
解释: 也可能序列中所有的数对都被返回:[1,3],[2,3]

⏳解题思路

  • 这道题其实就是topK问题,获取前k个最小的元素。这里的元素是一个数对值。
  • 创建一个大小为k的大根堆,存放前k个和最小的数对。
  • 给定的两个目标数组都是升序排列的,如果k小于数组的长度,那么数对中的一个数一定在数组前k个元素中。
  • 遍历两个数组中的元素,遍历次数:min(k,数组长度)【k,与数组长度的最小值】,构造数对值,将前k个数对放进大根堆,并调整。
  • 如果数对(两个数)的和比堆顶数对和小,则替换堆顶的元素,最终大根堆中的数对就是最小的k对数字。

🌊代码示例

class Solution {
    public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        PriorityQueue<List<Integer>> maxHeap = new PriorityQueue<>(k, new Comparator<List<Integer>>() {
            @Override
            public int compare(List<Integer> o1, List<Integer> o2) {
                return o2.get(0)+o2.get(1) - o1.get(0) - o1.get(1);
            }
        });
        for (int i = 0; i < Math.min(nums1.length,k); i++) {
            for (int j = 0; j < Math.min(nums2.length,k); j++) {
                 List<Integer> list = new ArrayList<>();
                    list.add(nums1[i]);
                    list.add(nums2[j]);
                if(maxHeap.size()<k){
                    maxHeap.offer(list);
                }else{
                    int top = maxHeap.peek().get(0) + maxHeap.peek().get(1);
                    if(top>nums1[i]+nums2[j]){
                        maxHeap.poll();
                        maxHeap.offer(list);
                    }else{
                        break;
                    }
                }
            }
        }
        List<List<Integer>> ret = new ArrayList<>();
        for (int i = 0; i < k && !maxHeap.isEmpty(); i++) {
            ret.add(maxHeap.poll());
        }
        return ret;
    }
}

六、PriorityQueue的比较方式

在了解 PriorityQueue 的比较方式前需要先了解对象的比较。

关于对象的比较在前面的文章中已经介绍过了。

文章导航:【JavaSE】----- 面向对象编程

简单回顾一下对象的比较。

关于对象的比较主要有三种方式:

  1. 重写父类的equals 方法,用于比较两个对象是否相同:如果两个对象相同,返回 true,否则就返回 false。
  2. 比较大小:实现 Comparable 接口或 Comparator 接口。

PriorityQueue底层使用堆结构,因此其内部的元素必须要能够比大小,PriorityQueue采用了:Comparble 和 Comparator两种方式。

  1. Comparble是默认的内部比较方式,如果用户插入自定义类型对象时,该类对象必须要实现Comparble接口,并覆写compareTo方法
  2. 用户也可以选择使用比较器对象,如果用户插入自定义类型对象时,必须要提供一个比较器类,让该类实现Comparator接口并覆写compare方法。

💥补充:优先级队列在插入元素时有个要求:

  • 插入的元素不能是null或者元素之间必须要能够进行比较。

插入元素为null的情况:

✨元素之间未指定比较规则(元素之间不能比较)的情况:

指定排序规则,对Card类的对象进行比较,通过比较的过程了解 PriorityQueue 底层的比较方式。

🍎方式一:实现 Comparable 接口

  • 注意:实现 Comparable 接口需要重写接口内部的抽象方法。

 🌊代码示例

import java.util.PriorityQueue;

//扑克牌
class Card implements Comparable<Card>{
    public int rank; // 数值
    public String suit; // 花色
    public Card(int rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }

    @Override
    //使用Comparable接口,需要重写compareTo方法
    //按照扑克牌的数值进行比较
    public int compareTo(Card o) {
        return this.rank - o.rank;
    }

    @Override
    //重写 toString 方法
    public String toString() {
        return "Card{" +
                "rank=" + rank +
                ", suit='" + suit + '\'' +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        //默认是小根堆
        PriorityQueue<Card> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(new Card(2, "♠"));
        priorityQueue.offer(new Card(1, "♠"));
        System.out.println(priorityQueue);
    }
}

❄运行结果

💦分析比较的过程

⭐将小根堆转换为大根堆

  • 将重写的 compareTo 方法的返回值交换一下位置就可以了。

这种方式对类的侵入性太强,一旦指定了比较规则,那么就不能轻易进行修改了。

🍎方式二:实现 Comparator 接口。

  • 创建一个类,实现 Comparator 接口。通过这个类确定对象比较的规则。

🌊代码示例 

//扑克牌
class Card {
    public int rank; // 数值
    public String suit; // 花色
    public Card(int rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }

    @Override
    //重写 toString 方法
    public String toString() {
        return "Card{" +
                "rank=" + rank +
                ", suit='" + suit + '\'' +
                '}';
    }
}

class RankComparator implements Comparator<Card> {

    @Override
    public int compare(Card o1, Card o2) {
        return o1.rank - o2.rank;
    }
}

public class Test {
    public static void main(String[] args) {
        Card card1 = new Card(1, "♠");
        Card card2 = new Card(2, "♠");
        RankComparator rankComparator = new RankComparator();
        //小根堆
        PriorityQueue<Card> priorityQueue = new PriorityQueue<>(rankComparator);
        priorityQueue.offer(card1);
        priorityQueue.offer(card2);
        System.out.println(priorityQueue);
    }
}

❄运行结果

💦分析比较的过程

🍎方式三:利用内部类实现(简写实现 Comparator接口的方法)

 🌊代码示例 

//扑克牌
class Card {
    public int rank; // 数值
    public String suit; // 花色
    public Card(int rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }

    @Override
    //重写 toString 方法
    public String toString() {
        return "Card{" +
                "rank=" + rank +
                ", suit='" + suit + '\'' +
                '}';
    }
}

public class Test {
    public static void main(String[] args) {
        Card card1 = new Card(1, "♠");
        Card card2 = new Card(2, "♠");
        PriorityQueue<Card> priorityQueue = new PriorityQueue<>(new Comparator<Card>() {
            @Override
            public int compare(Card o1, Card o2) {
                return o2.rank - o1.rank;
            }
        });
        priorityQueue.offer(card1);
        priorityQueue.offer(card2);
        System.out.println(priorityQueue);
    }
}

❄运行结果

lambda表达式,是上面方法的简写。

public class Test {
    public static void main(String[] args) {
        Card card1 = new Card(1, "♠");
        Card card2 = new Card(2, "♠");
        PriorityQueue<Card> priorityQueue = new PriorityQueue<>((x,y) -> {return y.rank-x.rank;} );
        priorityQueue.offer(card1);
        priorityQueue.offer(card2);
        System.out.println(priorityQueue);
    }
}
  • 这种写法代码虽然简洁,但是可读性很差。
  • 19
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潇湘夜雨.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值