java源码分析-优先队列

原创 2015年11月19日 09:14:02

愿她好!

优先队列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;
    }




如何理解 Java 中的 <T extends Comparable<? super T>>

source: http://www.cnblogs.com/xiaomiganfan/p/5390252.html Java 中类似 > 这样的类型参数 (Type Parameter) ...

优先队列子问题源码

  • 2014年07月08日 15:21
  • 558B
  • 下载

基于vc的堆、最大优先队列源码

  • 2012年08月22日 16:56
  • 4.79MB
  • 下载

Timer 源码解读 (2) TaskQueue 最小堆实现的优先队列

Timer中的定义:

优先队列算法实现(Java)

  • 2009年06月01日 12:49
  • 4KB
  • 下载

源码系列:堆排序、优先队列

priority_queue.h #ifndef PRIORITY_QUEUE_H_INCLUDED #define PRIORITY_QUEUE_H_INCLUDED #include #in...

优先队列操作

  • 2013年04月12日 15:59
  • 3KB
  • 下载

关于STL中优先队列的用法

  • 2010年01月02日 12:20
  • 2KB
  • 下载

(十六)java多线程之优先队列PriorityBlockingQueue

本人邮箱: kco1989@qq.com 欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco github: https://github.com/...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java源码分析-优先队列
举报原因:
原因补充:

(最多只允许输入30个字)