java 优先队列源码阅读

Java PriorityQueue阅读

优先队列使用最大或者最小堆来实现,使用数组来储存元素,将数组当做完全二叉树来处理,节点node的左右孩子节点为(2node+1和2node+2)
数组扩容:newCapacity =
oldCapacity+((oldCapacity<64) ?(oldCapacity+2) : (oldCapacity>>1));当newCapacity>Integer.MAX_VALUE - 8时,由private static int hugeCapacity(int minCapacity)处理
最后面的代码是我自己的仿写,有不确定的地方请参考源码

PriorityQueue参数介绍

参数名 作用
Object[] queue 保存输入的元素
size 已经存入的元素的数量
DEFAULT_INITIAL_CAPACITY 默认的队列初始化大小
Comparator comparator 比较存储的元素的顺序
int modCount 队列修改的次数

PriorityQueue的构造方法

构造方法分为两类:

  1. 根据参数进行构造,如:public PriorityQueue(int initialCapacity, Comparator comparator)
  2. 将Collection作为参数进行构造,如:public PriorityQueue(Collection c);其中的Collection可以为SortedSet,PriorityQueue或者其他实现自Collection的类

PriorityQueue的public方法

方法名 作用和使用
public boolean add(E e) 向队列中添加元素,调用offer方法实现
public boolean offer(E e) 向队列中添加元素,e==null抛出异常,否则返回true
public E peek() 返回优先队列中的第一个元素,及queue[0]
public boolean remove(Object o) 从队列中删除o元素,成功返回true,否则返回false
public boolean contains(Object o) 队列中是否存在元素o
public Object[] toArray() 返回队列中的元素(数组queue)的拷贝
public T[] toArray(T[] a) 将queue数组中的元素转换为T类型并拷贝到T[] a中,返回a
public Iterator iterator() 返回一个队列的Iterator对象
public void clear() 清空数组queue
public E poll() 删除并返回优先队列中的第一个元素(queue[0])

PriorityQueue的private方法

我在这里根据作用把他们分为三类:

  1. 增加队列的容积:
    private void grow(int minCapacity):在offer方法中使用,minCapactiy = queue.length+1;增加方法为:newCapacity =
    oldCapacity+((oldCapacity<64) ?(oldCapacity+2) : (oldCapacity>>1));

  2. 平衡队列中的数据顺序
    private void siftUp(int k,E x):k:当前元素的插入位置,x插入的元素,在增加元素和删除元素时被使用,但是这个方法不负责具体实现,只是用来判断队列中是否申明了Comparator,申明了调用私有方法siftUpUsingComparator方法去具体实现,否则调用siftUpComparable方法;下面会具体说明源代码的实现
    private void siftUpComparable(int k, E x):k和x同上,负责向上平衡queue(平衡方法可参考最小堆的平衡方法)平衡时的比较使用E的CompareTo方法
    private void siftUpUsingComparator(int k, E x):k和x同上,负责向上平衡queue(平衡方法可参考最小堆的平衡方法)平衡时的比较使用Comparator的规则
    还有向下平衡的三个私有方法:基本内容同上面三个方法
    private void siftDown(int k, E x):
    private void siftDownComparable(int k, E x):
    private void siftDownUsingComparator(int k,E x):

  3. 查和删除的辅助方法
    private int indexOf(Object o): 查找对象o在队列中的位置,在public类remove中被调用;
    private E removeAt(int i): 删除队列queue中位于第i位置的元素并平衡queue,在public类remove和私有类Iterator中的remove中被调用,下面会详细讲解这个方法;

主要源码讲解

  1. private void siftUpComparable(int k, E x)和private void siftUpUsingComparator(int k, E x)方法的实现:
/**
 * 在queue中的第k个位置(从位置0开始)放入x,并向上调整顺序
 *  与父节点比较,如果比父节点顺序靠前,与父节点位置交换 
 * @param k 开始时放入元素x的位置
 * @param x 放入的元素
 */private void siftUpComparable(int k, E x) {
    Comparable key=(Comparable)x;
    while (k>0){
        int parent=(k-1)>>>1;
        Object pNode=queue[parent];
        if(key.compareTo((E)pNode)>0)
            break;
        queue[k]=pNode;
        k=parent;
    }
    queue[k]=key;
}
  1. private void siftDownComparable(int k, E x)和private void siftDownUsingComparator(int k,E x)方法的实现:
/**
 * 在queue中的第loca个位置(从位置0开始)放入x,并向下调整顺序
 * 先找出子节点中顺序靠前的节点,再与父节点的顺序进行比较,如果顺序靠前的子节点的顺序在父节点的前面,父节点与子节点交换位置
 * @param loca 开始时放入元素x的位置
 * @param x 放入的元素
 */
pri
private void siftDownComparable(int loca,E x){
    Comparable key=(Comparable)x;
    int half=size>>>1;
    // size为保存元素的数组的大小,第n位的左右子节点为(2*n+1)和(2*n+2),所以当loca小于size/2时,loca不存在子节点
    while (loca0
        if(right)childNode).compareTo((E)queue[right])>0){
            childNode=queue[right];
            child=right;
        }
        if(key.compareTo((E)childNode)<=0)
            break;
        queue[loca]=childNode;
        loca=child;
    }
    queue[loca]=x;
}

  1. 内部类Iterator的实现
//这是一个很重要的函数,优先队列中的所有remove方法都掉用了这个方法来完成
/**
*作用删除在queue数组中位于第index的元素
*实现,使用数组末尾的元素来替换第index位的元素,替换后会先调用siftDown(向下平衡)方法,
*如果该元素没有向下移动(判断标准为位置是否变化),再使用siftUp方法向上平衡。
*该元素的最终位置小于index,返回该元素,否则返回null。返回值主要是在Iteretor的remove方法中用到,为了防止删除元素后,新填充的元素顺序比删除的元素顺序靠前而没有遍历。
*/
E removeAt(int index) {
    int s=--size;
    if(s==index){
        queue[index]=null;
    }else{
        E moved=(E)queue[s];
        siftDown(index,moved);
        //没有向下移动的时候,queue[index]与moved的引用相同
        if(queue[index]==moved){
            siftUp(index,moved);
            if (queue[index]!=moved)
                return moved;
        }
    }
    return null;
}
//这是迭代器的实现,这里面的next方法和remove方法是优先队列中最难理解的部分,
//remove使用前next方法必须被使用
private final class Itr implements Iterator{
    //当前遍历在queue中的位置
    private int cursor;
    //标记当前遍历的元素是在数组中还是在forgetMeNot,在forgetMeNot中lastRet=-1;
    private int lastRet=-1;
    //保存removeAt的返回值
    private ArrayDeque forgetMeNot;
    //当前遍历的元素
    private E lastRetElt;
    Itr(){}

    @Override
    public boolean hasNext() {
        return cursor();
                }
                forgetMeNot.add(moved);
            }
        }else if(lastRetElt!=null){
            PriorityQueueRewrite.this.removeEq(lastRetElt);
            lastRetElt=null;
        }else throw new IllegalStateException();
    }
}
  1. queue的接口的实现:
    添加:在数组末尾添加,然后向上平衡
    poll:返回数组头部元素,将数组末尾的元素移到首部,然后向下平衡
    实现详情请参考最大堆的的实现

你可能感兴趣的:(java源码学习,优先队列源码阅读)