PriorityQueue(优先级队列)源码分析

前言

     这篇博客主要内容是解决为什么优先级队列默认是小根堆的问题.

我们总是听老师讲,优先级队列默认是小根堆,大家思考过为什么是小根堆?而不是大根堆,是小根堆的话,它又是如何实现的呢?.接下来就让我们来探索一下.

可以看到下面的代码,我将两个学生对象放入优先级队列中,然后调试.

import java.util.PriorityQueue;

class Student implements Comparable<Student>{
    int age;
    public Student(int age){
        this.age = age;
    }

    @Override
    public int compareTo(Student o) {
        return this.age - o.age;
    }
}
class Test {

    public static void main(String[] args) {
        PriorityQueue<Student> queue = new PriorityQueue<>();
        queue.offer(new Student(5));
        queue.offer(new Student(10));
        System.out.println("123");
    }
}

可以看到上图调试的结果,第一个是5,第二个是10,说明是小根堆.

程序都是按照顺序进行的嘛,我就从main函数第一行代码开始分析.有下图可以看到,在我们实例化优先级队列时  DEFAULT_INITIAL_CAPACITY = 11 进入到构造方法中的方法时,可以看到initialCapacity = 11,不满足if条件,程序往下执行,初始化了queue这个数组,继续往下执行,比较器还是null,  main函数的第一行代码就走完了. 这时候就有人想问了,初始化queue这个数组有什么用呢? 请听下面分解.

然后就是第二行代码. 传入一个Student对象即e就是Student对象, modCount++不用管他,根据上面的分析可以知道,queue.length = 11, 所以不满足if中的条件. 右图可以看到源码中size默认是0,i就等于零.size在这个方法中变成了1,i = 0满足if中条件,queue数组0下标的值就是 age = 5的Student对象. 最后返回true结束方法. 第二行代码,主要是将Student对象放入queue数组的0下标.

下面来看第三行代码.按照正常逻辑来看,还是一样的结果,第一次我也搞错了,以为还是走一样的代码,程序就结束了,可是并没有结束.第一次调用offer方法的时候,size的值改变了,size = 1; 当第二次调用offer方法时,i != 0,会调用siftUp(i, e)方法,不满足条件,走else里面的方法.

走完siftUpComparable(int k, E x)方法,其实就干了一件事情,不满足小根堆就交换.使源码中的queue数组满足小根堆的格式.

     好了,到了这里,为什么优先级队列默认是小根堆的问题就解决了,博客还没有写完.

     那就有人要问了,可不可以把它改成大根堆?首先我们要明白一件事情,源码是改不了的,那就只能从别的地方入手,从哪里入手呢?分析一下:我们在调用offer这个方法的时候,先是将age = 10的学生对象放入queue数组中,然后将age = 5的学生对象放入queue数组中,这个时候已经是大根堆了,只是被改成了小根堆,那就可以这样思考,可不可以不改变数组queue   0下标和1下标的内容?

     答案是可以的.只需要将比较条件修改一下就行了,就会进入if,循环结束,不交换,key自己赋值给自己,内容没变.这就达到了大根堆的目的.

if (key.compareTo((E) e) >= 0) break;

  

改了比较的内容,调试结果如下图,就变成了大根堆了.

好了以上就是全部内容了,假如对你有帮助的话,不要忘了关注 点赞 收藏哦!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值