详解优先级队列(下)【手撕源码】

✨hello,愿意点进来的小伙伴们,你们好呐!
✨ 系列专栏:【数据结构】
本篇内容:手撕 PriorityQueue 源码
作者简介:一名现大二的三非编程小白

    • 前序
    • 解析源码
      • 1. 创建PriorityQueue对象
      • 2. 第一次Offer
      • 2. 第二次Offer
      • 3.实现Comparable接口
      • 4.实现添加元素
      • 5.大小根堆的调整
    • Integer的堆变化
      • Integer中的compareTo
      • 2. PriorityQueue(Comparator comparator)
      • 2. 传参 Comparator
      • 3.解析源码

在之前我们了解了如何自己来实现堆,现在我们来看看Java原码中,PriorityQueue是如何实现的呢?
接下来让我们一步一步来了解吧。

前序

我们创建一个Person类,类中有age成员变量。
创建PriorityQueue 对象,且往其中存放Person对象,来看看原码中是如何实现的

解析源码

1. 创建PriorityQueue对象

在这里插入图片描述

1.我们先创建一个PriorityQueue对象,来看一下底层是如何创建的。
详解优先级队列(下)【手撕源码】_第1张图片
2.可以看到PriorityQueue无参构造器在源码中会调用另一个构造器,传入一个整型与comparator对象,该整型是我们首次创建数组的大小。

详解优先级队列(下)【手撕源码】_第2张图片
3.我们可以看到在调用的构造器中,判断数组首次创建的大小是否大于1,否则抛异常,然后创建一个Object数组赋给quque,将 null赋给 comparator

在这里插入图片描述

在这里插入图片描述

这时候创建对象的代码完毕,最终结果在内存中创建了一个容量为11的Object数组

2. 第一次Offer

第一次offer比较特殊,因为在之前堆中是没有对象的,那么第一次给堆添加对象会发生什么呢?接下来让我们来瞧瞧

详解优先级队列(下)【手撕源码】_第3张图片
1. 先判断offer进去的对象是否为null,抛异常
详解优先级队列(下)【手撕源码】_第4张图片

2. 再来取出堆中的元素的个数,去判断是否堆已经满,满则扩容详解优先级队列(下)【手撕源码】_第5张图片

3. 最后再来判断是否是存储进堆第一个对象,很明细我们现在要存进去的是堆第一个对象,所以进入if语句中
详解优先级队列(下)【手撕源码】_第6张图片

目前为止,添加第一个对象完毕,接下来我们来看看添加第二次对象会有什么变化呢?

2. 第二次Offer

详解优先级队列(下)【手撕源码】_第7张图片

1.第二次offer时,会进入 siftUp 方法中。我们来看看该方法中会以什么方式来创建呢?
详解优先级队列(下)【手撕源码】_第8张图片

2. 在该方法中,因为创建PriorityQueue时并没有传入Comparator,所以会进入else语句中
详解优先级队列(下)【手撕源码】_第9张图片

3. k 是 原本对象应该存进堆中的位置,x是要存入的对象
详解优先级队列(下)【手撕源码】_第10张图片
4. 我们会看到在该方法会将所存入的对象强制转化成Comparable,所以我们得知在该情况下想要往堆中存放对象的时候,该对象类型要实现Comparable接口,但是Person并没有实现该接口,那么我们先来实现该接口再来继续往下看。
详解优先级队列(下)【手撕源码】_第11张图片

3.实现Comparable接口

详解优先级队列(下)【手撕源码】_第12张图片

4.实现添加元素

最后在下面代码中去给堆添加对象,并调节堆。

详解优先级队列(下)【手撕源码】_第13张图片

5.大小根堆的调整

详解优先级队列(下)【手撕源码】_第14张图片
我们可以看到目前的堆是小根堆,那么我们要怎么样才可以将小根堆调整为大根堆呢?
其实很简单,只要我们调整Person类中的compareTo的返回值即可。
详解优先级队列(下)【手撕源码】_第15张图片

在siftUpComparable中的if判断中就可以体现出

详解优先级队列(下)【手撕源码】_第16张图片

Integer的堆变化

上面我们找到了自定义类型的添加入堆中源码的解析,自定义类型添加入堆,必须实现Comparable接口才可以进行判断,那么现在我们会有一个疑问,那么要是存入的类型是Integer类型的元素呢?Integer中有继承Comparable接口与重写compareTo,那么会有一个判断的规则,所以有固定的大小根堆,但是我们怎么来将它的根堆转换呢?

Integer中的compareTo

在Integer中的compareTo调用compare
详解优先级队列(下)【手撕源码】_第17张图片

在该逻辑下,默认会将Integer类型的数据调整为小根堆。但是我们要怎么将其该成大根堆呢?

详解优先级队列(下)【手撕源码】_第18张图片

2. PriorityQueue(Comparator comparator)

这时候,就要来认识一下 PriorityQueue中的另一个构造器

1. 在该构造器中调用第一个构造器并传入参数。
详解优先级队列(下)【手撕源码】_第19张图片
2.在该构造器中,对comparator比较器赋值
详解优先级队列(下)【手撕源码】_第20张图片

认识了这个构造器后,我们应该怎么来传参呢?

2. 传参 Comparator

我们可以在创建PriorityQueue对象时传入匿名内部类Comparator,并重写compare方法。

详解优先级队列(下)【手撕源码】_第21张图片

3.解析源码

那么将与无参构造器不同的是在siftUp时会进入if语句
详解优先级队列(下)【手撕源码】_第22张图片

接下来的逻辑判断也与之前的一致的啦
详解优先级队列(下)【手撕源码】_第23张图片

关于PriorityQueue的源码就介绍到这里,欢迎大佬们指点

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