美文网首页
PriorityQueue优先级队列源码分析

PriorityQueue优先级队列源码分析

作者: 在岁月中远行 | 来源:发表于2023-02-27 01:32 被阅读0次

从名字上看,PriorityQueue叫做优先队列,它的另一个名字也叫堆(heap),这个名字更熟悉。它和普通的队列不太一样,它里面存储的元素具有一定的顺序性,而不是简单的先进先出。它的实现原理通常是一颗完全二叉树。

优先队列的整体结构虽然是一个二叉堆,也是树结构。但是存储元素却是用数组实现的。

这就是一颗完全二叉树,转换为数组的话就是[50,22,70,10,5]

假设优先队列的第一个元素的索引就是数组中索引为0的元素,其中优先队列的一个节点对应数组的索引是parent,那么左儿子节点索引就是left,右儿子节点索引是right,则存在下面的关系:

left=2*parent+1;right=left+1

parnet=left/2 ;parent=(right-1)/2

先看构造方法:

构造函数

默认容量大小为11

保存元素的数组,同样是一个二叉堆

集合队列元素数量size

比较器,自定义比较逻辑,决定是大根堆还是小根堆

集合修改次数

根据几个成员变量,可以知晓PriorityQueue内部使用数组实现二叉堆,默认的容量为11。

这里这个queue的成员变量的数组长度就是initialCapactity容量大小。

下面我们来分析下offer方法:

当队列元素大小大于等于这个内部数组大小时就扩容,下面我们来看扩容grow方法。

扩容的本质也是利用Arrays.copyOf方法进行元素复制,重点在于数组的大小

oldCapacity<64   -> newCapacity=oldCapacity*2+2

oldCapacity>64   -> newCapac=1.5*oldCapacity

https://www.bilibili.com/video/BV1tW411j7dL/?spm_id_from=333.999.0.0&vd_source=651b32e608fe895ed2b8d03e9549740b(4:45秒开始这个视频讲的非常好动画)

下面来说下当执行aaa.offer(26)过程:

当执行到siftUpComparable方法时,这里的参数k为8(以前队列元素就是8个),x为添加的元素26。

1 将x(26)强制转换成key,为了方便比较。

2 开启while循环,获取parent节点为:(8-1)>>>1 =3,设置e为40

3 比较26与40大小,key<e,那么就将queue[8]=40,

4 下一步将parent赋值给k,这时k=3。再执行获取e元素,这时e元素为queue[(3-1)/2]=1,比较queue[1]=30,与26大小,key还是小于e,那么就将queue[3]=30,

这时候k=1,parent=0,比较26与10大小,不满足,结束循环。

最后queue[1]=26。    ( 始终是拿26与父节点去比较。 )

这里也可以证明是上述是对的queue[1]为26,queue[3]=30,queue[8]=40。

下面我们来看poll方法:

调用poll方法,会删除最小元素,即堆顶元素。

删除之后,若把末尾元素直接放到堆顶,则破坏了堆的平衡。

先举个例子:

在执行aaa.poll方法之前元素二叉树这么排列的。

接下来就会调用siftDownComparable(int k, E x) 此时这里的k为0,x为40。

排列的

1 强转,方便使用compareTo方法进行比较。

2 获取half值,这里一直循环到是叶子节点。half=8/2=4

3 开始循环,获取child的值为k=0*2+1=1

4 获取queue[1]=26; right=1+1=2;queue[2]=20;

5 如果右节点right<size表面存在右节点,且左右节点比较。如果右子节点的元素比左子节点的元素小,那么使用右子节点的值。将right赋值给child,并且将queue[child=right],如果右节点大的话比左节点,那么c就是原来左节点的值。

6 如果key=x=40和c左右节点的最小值比较,40>queue[2],那么queue[0]=c=20;

7 将child=2赋值给k,此时k=2。

第二次循环:

获取child=2*2+1=5 right=6 ;queue[left]=50;queue[right]=25; 所以再拿25和key=40比较,那么queue[K=2]=25,再执行k=child,此时k=6;再来执行while(k<half)进不去循环体内容,直接跳出,执行queue[k]=key 。那么queue[6]=40。

所以queue[0]=20;queue[2]=25;queue[6]=40;

相关文章

  • JAVA优先级队列详解及源码剖析

    JAVA优先级队列详解及源码剖析 PriorityQueue PriorityQueue是在JDK1.5之后出现的...

  • 优先级队列PriorityQueue源码分析

    优先级队列是一种抽象数据类型。优先队列中的每个元素都有各自的优先级,优先级最高的元素最先得到服务;优先级相同的元素...

  • PriorityQueue优先级队列源码分析

    从名字上看,PriorityQueue叫做优先队列,它的另一个名字也叫堆(heap),这个名字更熟悉。它和普通的队...

  • java笔记

    [java优先队列PriorityQueue的使用] PriorityQueue弹出优先级最高的元素,优先级的比较...

  • PriorityQueue优先队列

    基于堆排实现优先队列 死磕 java集合之PriorityQueue源码分析

  • PriorityQueue源码学习

    PriorityQueue源码学习 使用堆来实现一个优先级队列,comapreTo()比较最小的那个放在堆顶,每次...

  • Java PriorityQueue

    以下内容转载至PriorityQueue详解 概念 PriorityQueue 一个基于优先级的无界优先级队列。优...

  • Java8 PriorityQueue 源码解析

    PriorityQueue 优先级队列 前世今生 extends AbstractQueueAbstractQue...

  • 队列

    什么是Java优先级队列(Priority Queue)? 考察点:队列参考回答: PriorityQueue是一...

  • 死磕 java集合之PriorityQueue源码分析

    问题 (1)什么是优先级队列? (2)怎么实现一个优先级队列? (3)PriorityQueue是线程安全的吗? ...

网友评论

      本文标题:PriorityQueue优先级队列源码分析

      本文链接:https://www.haomeiwen.com/subject/bnnfldtx.html