PriorityQueue源码分析
//默认初始容量是11
private static final int DEFAULT_INITIAL_CAPACITY = 11;
transient Object[] queue; // non-private to simplify nested class access
//容量大小
private int size = 0;
//比较器
private final Comparator<? super E> comparator;
//优先队列被修改的次数
transient int modCount = 0; // non-private to simplify nested class access
可以看出来PriorityQueue底层是一个Object类型的数组
构造函数 经典套娃
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
public PriorityQueue(Comparator<? super E> comparator) {
this(DEFAULT_INITIAL_CAPACITY, comparator);
}
//传入初始容量,和构造器
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
// Note: This restriction of at least one is not actually needed,
// but continues for 1.5 compatibility
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
add()方法 add方法就是调用的offer方法所以直接贴offer的源码了
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
//操作次数加1
modCount++;
int i = size;
if (i >= queue.length)
//如果数量>=数组长度 扩容
grow(i + 1);
size = i + 1;
if (i == 0)
queue[0] = e;
else
//真正的添加元素
siftUp(i, e);
return true;
}
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
//不添加比较器的方法
//k是size值就是最新插入节点的位置 二叉树的位置就是最底层叶子节点的最右位置
private void siftUpComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>) x;
while (k > 0) {
//找到父节点的位置 减1 再/2
int parent = (k - 1) >>> 1;
//获取父节点的值
Object e = queue[parent];
//比较器比较如果当前值比父节点要大的话就跳出循环
if (key.compareTo((E) e) >= 0)
break;
//于父节点交换位置 再于父节点的父节点进行比较
queue[k] = e;
k = parent;
}
//找到插入位置进行插入
queue[k] = key;
}
扩容
private void grow(int minCapacity) {
int oldCapacity = queue.length;
//如果小于64就翻倍 大于64增加原来的一半
// Double size if small; else grow by 50%
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) :
(oldCapacity >> 1));
// overflow-conscious code
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
poll方法
public E poll() {
if (size == 0)
return null;
int s = --size;
modCount++;
//获取第一个元素的值
E result = (E) queue[0];
//获取最后一个元素的值
E x = (E) queue[s];
//删除最后一个元素
queue[s] = null;
if (s != 0)
siftDown(0, x);
return result;
}
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
@SuppressWarnings("unchecked")
private void siftDownComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>)x;
//从非叶子节点开始因为叶子节点占了一半
int half = size >>> 1;// loop while a non-leaf
while (k < half) {
//获取k位置的左孩子
int child = (k << 1) + 1; // assume left child is least
Object c = queue[child];
//右孩子
int right = child + 1;
//获取到左右孩子中较小的值
if (right < size &&
((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
c = queue[child = right];
//如果key的值比左右孩子节点都小了就退出
if (key.compareTo((E) c) <= 0)
break;
//交换于最小子节点的位置
queue[k] = c;
//交换key值
k = child;
}
//找到合适的位置
queue[k] = key;
}
indexof方法 如果让我写这个方法的话因为底层是数组所以就直接遍历输出下标位置就ok了 看看源码
private int indexOf(Object o) {
if (o != null) {
for (int i = 0; i < size; i++)
if (o.equals(queue[i]))
return i;
}
return -1;
}
牛逼和我想法一摸一样 我可以去oracle开发最新的jdk了吗
好吹个牛逼。学习完了priorityQueue的常用方法的构造 那么就重复造轮子加深一下自己的理解!
跟源码一模一样哈哈哈哈但是原理已经比较清楚了但是还没测试,先去吃口饭吃完饭回来测试一下
package com.czq.wheel;
import java.io.Serializable;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Iterator;
/**
* Created By 丛梓祺 on 2021/10/23
* Write this code and change the world
*/
public class MyPriorityQueue<E> extends AbstractQueue<E> implements Serializable {
/**
* 默认堆大小
*/
private static final int DEFAULT_SIZE = 11;
/**
* 元素个数
*/
private int size;
/**
* 堆
*/
transient Object[] queue;
/**
* 比较器
*/
private final Comparable<? super E> comparator;
public MyPriorityQueue() {
this(DEFAULT_SIZE, null);
}
public MyPriorityQueue(int initValue, Comparable<? super E> comparable) {
queue = new Object[initValue];
this.comparator = comparable;
}
@Override
public boolean offer(E e) {
int i = size;
if (i >= queue.length)
grow(i + 1);
size++;
if (i == 0) {
queue[0] = e;
} else {
siftUp(i, e);
}
return true;
}
private void siftUp(int i, E addValue) {
Comparable<? super E> key = (Comparable<? super E>) addValue;
while (i > 0) {
//找到父节点
int parent = (i - 1) >>> 1;
Object parentValue = queue[parent];
if (key.compareTo((E) parentValue) >= 0) {
break;
}
//交换父节点的值
queue[i] = parentValue;
i = parent;
}
queue[i] = key;
}
@Override
public E poll() {
if (size == 0) return null;
Object result = queue[0];
int s = --size;
Object lastValue = queue[s];
queue[s] = null;
if (s != 0) {
siftDown(0, (E) lastValue);
}
return (E) result;
}
private void siftDown(int i, E lastValue) {
Comparable<? super E> key = (Comparable<? super E>) lastValue;
int half = size >>> 1;
while (i < half) {
int child = (i << 1) + 1;
//假设是左子树
Object minChild = queue[child];
int right = child + 1;
if (right < size && ((Comparable<? super E>) minChild).compareTo((E) queue[right]) > 0) {
//更换最小值
minChild = queue[child = right];
}
if (key.compareTo((E) minChild) <= 0) {
break;
}
queue[i] = minChild;
i = child;
}
queue[i] = key;
}
@Override
public E peek() {
return size == 0 ? null : (E) queue[0];
}
//就不考虑极值情况了
public void grow(int size) {
int oldSize = size;
int newSize = oldSize + ((oldSize > 64) ? oldSize : oldSize / 2);
queue = Arrays.copyOf(queue, newSize);
}
@Override
public Iterator<E> iterator() {
return null;
}
@Override
public int size() {
return size;
}
}
最开始再删除的时候
这里如果右子树没有值那么就不用走循环了,所以最开始没写这个会有空指针的情况
测试结果: