`

集合框架 Queue篇(2)---PriorityQueue

 
阅读更多
Queue

------------
1.ArrayDeque,
2.PriorityQueue,
3.ConcurrentLinkedQueue,

4.DelayQueue,
5.ArrayBlockingQueue,
6.LinkedBlockingQueue,
7.LinkedBlockingDeque
8.PriorityBlockingQueue,
9.SynchronousQueue
------------

---------------------------------------

PriorityQueue(优先级队列)
/**
*PriorityQueue是一个优先级堆(二叉堆)的无界优先级队列。
*优先级队列的元素按照其自然顺序(Comparable)进行排序,或者根据构造队列时提供的Comparator进行排序,具体取决于所使用的构造方法。
*优先级队列不允许使用null元素。依靠自然顺序的优先级队列还不允许插入不可比较的对象(否则会导致ClassCaseException)。
*此队列的头是按指定排序方式确定的最小元素。如果多个元素都是最小值,则头是其中一个元素--选择方法是任意的。
*队列获取操作 poll、remove、peek和element访问处于队列头的元素。
*优先级队列是无界的,但是有一个内部容量,控制着用于存储队列元素的数组大小。它至少等于队列的大小。随着不断向优先级队列
*添加元素,其容量会自动增加。无需指定容量增加策略的细节。
*/
public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {
    private static final int DEFAULT_INITIAL_CAPACITY = 11;//默认的初始容量为11

    /**
     * 优先队列是通过“平衡二叉堆”的形式实现的:
     * 对于数组queue中任一元素queue[n],其左儿子为queue[2*n+1],右儿子为queue[2*(n+1)];
     * 优先级队列的元素按照其自然顺序(Comparable)进行排序,或者根据构造队列时提供的Comparator进行排序,
     * 具体取决于所使用的构造方法。
     * 在堆中,对于每个节点n,n的父节点中的关键字小于或等于n中的关键字,根节点也就是queue[0]是最小的。
     */
    private transient Object[] queue;

    private int size = 0;//优先级队列中元素的个数

    /**
     * 节点的关键字“比较器”,如果为null则采用关键字的自然排序(Comparable)方式
     */
    private final Comparator<? super E> comparator;

    /**
     * 优先队列结构变动的次数
     */
    private transient int modCount = 0;

    /**
     * 无参构造,采用默认容量及元素的自然排序(Comparable)形式
     */
    public PriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }

    /**
     * 指定容量
     */
    public PriorityQueue(int initialCapacity) {
        this(initialCapacity, null);
    }

    /**
     * 指定容量及排序器
     */
    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;
    }

    /**
     * 通过“集合”初始化队列并根据集合的类型初始化排序器
     */
    public PriorityQueue(Collection<? extends E> c) {
        initFromCollection(c);
        if (c instanceof SortedSet)
            comparator = (Comparator<? super E>)
                ((SortedSet<? extends E>)c).comparator();
        else if (c instanceof PriorityQueue)
            comparator = (Comparator<? super E>)
                ((PriorityQueue<? extends E>)c).comparator();
        else {
            comparator = null;
            heapify();
        }
    }

    /**
     * 通过另一个“优先队列”初始化队列及其排序方式
     */
    public PriorityQueue(PriorityQueue<? extends E> c) {
        comparator = (Comparator<? super E>)c.comparator();
        initFromCollection(c);
    }

    /**
     * 通过“排序集合”初始化队列及其排序方式
     */
    public PriorityQueue(SortedSet<? extends E> c) {
        comparator = (Comparator<? super E>)c.comparator();
        initFromCollection(c);
    }

    /**
     * 通过集合初始化数组
     */
    private void initFromCollection(Collection<? extends E> c) {
        Object[] a = c.toArray();
        // If c.toArray incorrectly doesn't return Object[], copy it.
        if (a.getClass() != Object[].class)
            a = Arrays.copyOf(a, a.length, Object[].class);
        queue = a;
        size = a.length;
    }

    /**
     *增加数组容量
     */
    private void grow(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
 int oldCapacity = queue.length;
        // Double size if small; else grow by 50%
        int newCapacity = ((oldCapacity < 64)?
                           ((oldCapacity + 1) * 2):
                           ((oldCapacity / 2) * 3));
        if (newCapacity < 0) // overflow
            newCapacity = Integer.MAX_VALUE;
        if (newCapacity < minCapacity)
            newCapacity = minCapacity;
        queue = Arrays.copyOf(queue, newCapacity);
    }

    /**
     * 插入元素
     */
    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);//通过堆的“上滤”方式插入新的元素(i是最后一个元素的位置)
        return true;
    }
    //获得队头元素
    public E peek() {
        if (size == 0)
            return null;
        return (E) queue[0];
    }
    //遍历得到元素o的索引
    private int indexOf(Object o) {
 if (o != null) {
            for (int i = 0; i < size; i++)
                if (o.equals(queue[i]))
                    return i;
        }
        return -1;
    }

    /**
     * 删除元素(通过equals的方式)
     */
    public boolean remove(Object o) {
 int i = indexOf(o);
 if (i == -1)
     return false;
 else {
     removeAt(i);
     return true;
 }
    }

    /**
     * 删除元素(通过==(引用相等)的方式)
     */
    boolean removeEq(Object o) {
 for (int i = 0; i < size; i++) {
     if (o == queue[i]) {
                removeAt(i);
                return true;
            }
        }
        return false;
    }

    /**
     * 是否包含
     */
    public boolean contains(Object o) {
 return indexOf(o) != -1;
    }

    /**
     * 返回队列元素的Object数组
     */
    public Object[] toArray() {
        return Arrays.copyOf(queue, size);
    }

    /**
     * 返回指定返回类型队列元素的数组
     */
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(queue, size, a.getClass());
 System.arraycopy(queue, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }
    
    //遍历器
    public Iterator<E> iterator() {
        return new Itr();
    }
    private final class Itr implements Iterator<E> {
      ……
    }

    public int size() {
        return size;
    }

    /**
     * 清空队列
     */
    public void clear() {
        modCount++;
        for (int i = 0; i < size; i++)
            queue[i] = null;
        size = 0;
    }
    //出对
    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 E removeAt(int i) {
        assert i >= 0 && i < size;
        modCount++;
        int s = --size;
        if (s == i) // 如果是最后一个元素,直接删除
            queue[i] = null;
        else { //否则,还要考虑删除位置i元素后,最后一个元素重新安排位置的问题
            E moved = (E) queue[s];
            queue[s] = null;
            siftDown(i, moved);//“下滤”策略
            if (queue[i] == moved) {//为了应对“迭代器”执行期间进行的remove操作,而导致的“Unlucky”元素设置的。
                siftUp(i, moved);
                if (queue[i] != moved)
                    return moved;
            }
        }
        return null;
    }

    /**
     *优先队列的“插入操作”时调用该“上滤”策略 :(主要是安排“插入的新元素”的合适位置)
     *为了将一个元素x插入到堆中,我们在下一个可用位置(就是最后一个叶子节点的下一个节点处)
     *创建一个空穴,否则该堆不是完全树。如果x可以放在该空穴中并不破坏堆的序,那么就插入完成。
     *否则,我们把空穴的父节点上的元素移入空穴中,这样空穴就朝着根的方向向上冒一步。继续改过程
     *直到x能被放入空穴中为止。
     *
     * 也就是,从位置k(该类中传入的k为最后一个元素的位置)处插入元素x,为了保证堆序性质,
     * 就对x进行“上滤”操作直到x为叶子节点或者小于等于它的孩子节点。
     */
    private void siftUp(int k, E x) {
        if (comparator != null)//比较器为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)//key>=父时,就表示该位置适合插入,
                break;
            //key比父小时,父就下移,k指定到原来父的位置,继续“上移”循环,直到key>=父或者k=0(为根)
            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;
    }

    /**
     *优先队列(二叉堆)的“删除操作”时调用该“下滤”策略 :(主要是安排最后一个元素的位置)
     *当删除一个最小元时,要在根节点建立一个空穴。由于现在少了一个元素,因此堆中最后一个元素x必须移动到某个
     *位置。如果x可以放在空穴中,那么操作结束,否则将空穴的两个儿子中的较小者移入空穴,这样空穴就向下推进一层。
     *重复该步骤直到x可以被放入空穴中。因此,我们的做法就是将x置于沿着k开始包含最小儿子的一条路径上的一个正确
     *位置。
     * 优先队列(小顶堆)的删除操作一般指的删除最小元(堆顶,根节点),当然也可以是k位置。
     * 也就是把位置k处设为空穴,对(最后一个元素)x进行“下滤”操作 直到x为叶子节点或者小于等于它的孩子节点。
     */
    private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }
    //“下滤”操作,通过关键字的comparable比较元素大小
    private void siftDownComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>)x;
        int half = size >>> 1;        // 循环非叶子节点(因为最后一个元素位于叶子节点处,只在叶子节点以上的部分寻找)
        while (k < half) {//k是指删除的元素的位置
            int child = (k << 1) + 1; // 左儿子位置
            Object c = queue[child];
            int right = child + 1;    // 右儿子位置
            //如果右儿子不是最后一个节点,c指向小节点
            if (right < size &&
                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
                c = queue[child = right];
            if (key.compareTo((E) c) <= 0)//如果key不大于其孩子节点,说明该空穴位置k可以插入了
                break;
            //如果key>它的最小子节点c,就“下滤”循环
            queue[k] = c;
            k = child;
        }
        queue[k] = key;
    }
    //“下滤”操作,通过Comparator(比较器)比较元素大小
    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;
    }

  ……

}
分享到:
评论

相关推荐

    11.集合框架001-Collection接口13-16

    "14-集合框架014-优先队列PriorityQueue-1080P 高清-AVC.mp4"重点介绍了优先队列(PriorityQueue)。优先队列不同于普通队列,它的元素按照优先级排序,当从队列中移除元素时,会默认移除优先级最高的元素。在Java中...

    java 集合(list-queue-set)学习

    Queue是Java集合框架中的队列接口,用于处理先进先出(FIFO)的数据结构。LinkedList除了实现List接口外,还实现了Deque接口,因此它能作为双端队列使用,支持头尾插入和删除。ArrayDeque是另外一种高效的双端队列...

    java集合框架图

    在Java集合框架中,主要有六种核心接口:`Collection`, `Set`, `List`, `Queue`, `Deque`, 和 `Map`。此外,还有五个抽象类以及多个实现类,它们共同构成了Java集合框架的基础。 #### 二、核心接口介绍 1. **`...

    Java 集合框架(1-9)-Collection 类关系图.pdf

    Java集合框架是Java编程语言中的一个核心组成部分,它提供了一套通用的数据结构和容器,用于存储和管理对象。集合框架自JDK 1.2引入以来,极大地提升了开发效率,优化了程序性能,并增强了不同API之间的互操作性。在...

    集合框架总结图

    集合框架是Java编程语言中的一个核心部分,它提供了一套高效、灵活的数据结构和算法,使得开发者能够方便地管理和操作对象。本总结图详细而全面地涵盖了Java集合框架的主要概念和组件,对于初学者和有经验的开发人员...

    java集合框架专题-java面试经典

    ### Java集合框架专题详解 #### 一、Java集合框架概览 Java集合框架是一个用于存储和操作对象集合的标准API。该框架提供了多种容器类型,包括`Collection`和`Map`两大类。 - **Collection**:这是一个接口,表示...

    Implementation-of-Queue-in-Java

    Java集合框架提供了一个名为`java.util.Queue`的接口,它是`Collection`接口的子接口。这个接口定义了队列操作的基本方法,如`add(E e)`(入队)、`remove()`(出队)、`element()`(获取但不移除队头元素)等。 3...

    java集合框架

    Java集合框架是Java编程语言中一个至关重要的组成部分,它为数据存储、管理和操作提供了丰富的类库。这个框架包括了接口、类以及它们之间的关系,旨在高效地处理各种数据结构。全面接触Java集合框架意味着要深入理解...

    集合框架代码及PPT、API.rar

    2. **集合框架中的接口** - **List接口**:代表有序的元素集合,允许有重复元素。ArrayList和LinkedList是它的主要实现类。 - **Set接口**:不允许有重复元素,提供了HashSet和TreeSet等实现。 - **Queue接口**:...

    Java-collection-frame.rar_Java集合框架

    Java集合框架是Java编程语言中一个至关重要的组成部分,它为数据存储、管理和操作提供了丰富的类库。这个框架包括了各种接口、类以及实现,使得开发者能够高效地处理对象的集合,无论是小型还是大型数据集。在Java...

    Java集合框架全景:深入理解主要接口和类

    Java集合框架主要包括四种类型的集合:List、Set、Queue和Map。每种集合都有其独特的特性和应用场景。 - **List**:有序集合,支持元素重复。典型实现包括`ArrayList`和`LinkedList`。 - **Set**:无序集合,不支持...

    集合框架和泛型机制的解释

    集合框架包含了多种类型的容器,如List、Set和Queue等,它们各自有不同的特性以满足不同场景的需求。例如,List接口代表了一个有序的元素列表,允许重复元素,并提供了按索引访问元素的能力;Set接口则不允许重复...

    JAVA:PriorityQueue

    `PriorityQueue`是Java集合框架的一部分,它是一个基于优先级堆的无界优先级队列。这个队列的元素可以按照它们的自然顺序或者是通过构造队列时提供的`Comparator`进行排序。`PriorityQueue`不允许使用`null`元素,...

    Java集合框架常见面试题.7z

    Java集合框架是Java编程语言中的一个核心组件,它为存储、管理和操作对象提供了一组统一的接口和类。面试中,对于Java开发者来说,对集合框架的理解和熟练应用通常是评估其技能的重要方面。以下是一些关于Java集合...

    java集合框架全面进阶

    本篇文章将深入探讨Java集合框架的各个方面,帮助开发者从基础到高级全面掌握这一关键知识。 首先,我们要理解Java集合框架的基础概念。集合是对象的容器,可以容纳多个对象,而框架则是一组接口和实现这些接口的类...

    全面接触Java集合框架

    Java集合框架是Java编程语言中不可或缺的一部分,它提供了一种高效、灵活的方式来存储和操作数据。这个框架包括了各种接口和类,它们为开发者提供了多种数据结构,如数组、链表、队列、堆栈、映射等。下面将详细探讨...

    java集合框架PPT

    1. **集合接口**:集合框架的核心是若干个接口,包括`List`、`Set`、`Queue`和`Map`。这些接口定义了各种数据结构的行为,如有序列表、无重复元素集合、队列以及键值对映射。 - `List`接口:线性结构,元素有顺序...

    集合框架与泛型课件

    Java集合框架包括接口(如List、Set、Queue)和实现这些接口的类(如ArrayList、HashSet、LinkedList等)。这些接口定义了通用的操作,如添加元素、删除元素、遍历元素等。通过使用这些接口,开发者可以编写出更灵活...

    一个讲解很清晰的Java集合框架PPT

    在Java中,集合框架主要包括四大接口:List、Set、Queue和Map。每个接口都有自己的特性和用途,适用于不同的数据组织需求。 1. **List接口**:List是有序的集合,允许元素重复,并且支持索引访问。ArrayList和...

    全面接触java集合框架(word版)

    Java集合框架是Java编程语言中的一个核心特性,它为存储、管理和操作对象提供了一套统一的接口和实现。这个框架包括各种接口、类和算法,使得开发者能够更加高效地处理对象集合,而无需关注底层数据结构的实现细节。...

Global site tag (gtag.js) - Google Analytics