您的位置:首页 > 编程语言 > Java开发

java源码分析-优先队列

2015-11-19 09:14 691 查看
愿她好!

优先队列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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: