PriorityQueue源码分析

本文详细解读了Java PriorityQueue的源码,并通过模仿创建了一个简易的MyPriorityQueue实现,探讨了核心方法如添加、删除和查找。通过实例展示了如何利用Comparable接口和数组结构管理元素优先级。
摘要由CSDN通过智能技术生成

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;
    }
}

最开始再删除的时候

这里如果右子树没有值那么就不用走循环了,所以最开始没写这个会有空指针的情况

测试结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值