java源码分析-优先队列

来源:互联网 发布:python import路径 编辑:程序博客网 时间:2024/06/14 17:25

愿她好!

优先队列PriorityQueue

1.类结构



2.优先队列分析
主要是怎么确定优先级
首先我们来看下add(E)方法
 public boolean add(E e) {        return offer(e);    }
 public boolean offer(E e) {        if (e == null)            throw new NullPointerException();        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);    }
private void siftUpComparable(int k, E x) {        Comparable<? super E> key = (Comparable<? super E>) x;        while (k > 0) {            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 siftUpUsingComparator(int k, E x) {        while (k > 0) {            int parent = (k - 1) >>> 1;            Object e = queue[parent];            if (comparator.compare(x, (E) e) >= 0)                break;            queue[k] = e;            k = parent;        }        queue[k] = x;    }

从上述代码可以看出:第一,add方法实际上是调用offer方法;第二,加入的元素不能为空,都在抛出空指向异常,这类问题在有序的集合中都会存在;第三,若队列满了,则采用grow方法扩容;第四,通过siftUp来重整队列,如果没有从外部传入比较器,采用siftUpUsingComparator方法来重整;否则,利用传入的比较器以及siftUpComparable来重整队列。


怎么比较优先级的?以自带的比较器为例子
关键代码在于parent的确定:int parent=(k-1)>>>1; 不断地找到中值,并利用比较器比较,直到比较器判断为true

java中有三种移位运算符

<<      :     左移运算符,num << 1,相当于num乘以2

>>      :     右移运算符,num >> 1,相当于num除以2

>>>    :     无符号右移,忽略符号位,空位都以0补齐

无符号右移的规则只记住一点:忽略了符号位扩展,0补最高位  无符号右移运算符>>> 只是对32位和64位的值有意义


扩容
private void grow(int minCapacity) {        int oldCapacity = queue.length;        // 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);    }

分为两种情况:如果原有容量小于64,扩容方式为加倍再加2;否则,每次增加原有容量的一半

最大容量
  private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 private static int hugeCapacity(int minCapacity) {        if (minCapacity < 0) // overflow            throw new OutOfMemoryError();        return (minCapacity > MAX_ARRAY_SIZE) ?            Integer.MAX_VALUE :            MAX_ARRAY_SIZE;    }



数组可能保留一些特殊字段

查找

 public E peek() {        if (size == 0)            return null;        return (E) queue[0];    }

 private int indexOf(Object o) {        if (o != null) {            for (int i = 0; i < size; i++)                if (o.equals(queue[i]))                    return i;        }        return -1;    }

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;    }
 
poll方法说明:第一,首先判断size是否为0;其次,弹出下标为0的元素,然后将下标为size-1的值放入下标为0的地方,并且重新排序

private void siftDown(int k, E x) {        if (comparator != null)            siftDownUsingComparator(k, x);        else            siftDownComparable(k, x);    }    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) {            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];            if (key.compareTo((E) c) <= 0)                break;            queue[k] = c;            k = child;        }        queue[k] = key;    }    private void siftDownUsingComparator(int k, E x) {        int half = size >>> 1;        while (k < half) {            int child = (k << 1) + 1;            Object c = queue[child];            int right = child + 1;            if (right < size &&                comparator.compare((E) c, (E) queue[right]) > 0)                c = queue[child = right];            if (comparator.compare(x, (E) c) <= 0)                break;            queue[k] = c;            k = child;        }        queue[k] = x;    }




0 0