集合类Queue(ArrayDeque/PriortyQueue)总结

一、ArrayDeque

简介

ArrayDeque类是双端队列的实现类,继承自AbastractCollection其实现的接口Deque接口中定义了双端队列的主要的方法,不允许null元素存在,实现了Cloneable、Serializable 接口,支持复制、序列化的。

成员变量

transient Object[] elements;
transient int head;
transient int tail;
private static final int MIN_INITIAL_CAPACITY = 8;

head指向第一个有效元素位置,tail指向尾部第一个可以插入元素的空闲位置。

构造函数

public ArrayDeque() {
        elements = new Object[16];
    }

无参构造函数,构造了一个大小为16的ArrayDeque。

public ArrayDeque(int numElements) {
        allocateElements(numElements);
    }
private void allocateElements(int numElements) {
        int initialCapacity = MIN_INITIAL_CAPACITY;
        // Find the best power of two to hold elements.
        // Tests "<=" because arrays aren't kept full.
        if (numElements >= initialCapacity) {
            initialCapacity = numElements;
            initialCapacity |= (initialCapacity >>>  1);
            initialCapacity |= (initialCapacity >>>  2);
            initialCapacity |= (initialCapacity >>>  4);
            initialCapacity |= (initialCapacity >>>  8);
            initialCapacity |= (initialCapacity >>> 16);
            initialCapacity++;

            if (initialCapacity < 0)   // Too many elements, must back off
                initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
        }
        elements = new Object[initialCapacity];
    }

有参构造调用allocateElements(numElements),当用户要求分配的数组大小小于8时,分配8个空间。当用户要求分配的数组大小大于8时则分配大于用户需要内存的2的最小幂,最大分配2 ^ 30 大小的数组。

public ArrayDeque(Collection<? extends E> c) {
        allocateElements(c.size());
        addAll(c);
    }

传入容器的构造函数。

操作方法

addFirst

    public void addFirst(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[head = (head - 1) & (elements.length - 1)] = e;
        if (head == tail)
            doubleCapacity();
    }

判断传入参数是否合法,不合法抛出空指针异常。head值先减1,然后将元素放到head位置, 如果head == tail 将数组大小扩大一倍。(head - 1) & (elements.length - 1) 使head的值在【0, elements.length - 1】范围之内,head一直围着数组转圈。head=tail时,数组中的元素已经满了,所以会将数组的扩大一倍。

addLast

 public void addLast(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[tail] = e;
        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
            doubleCapacity();
    }

如果传入元素为null,抛出空指针异常。将传入值赋给tail位置。

removeFirst

 public E removeFirst() {
        E x = pollFirst();
        if (x == null)
            throw new NoSuchElementException();
        return x;
    }

removeFirst方法调用了pollFirst方法,当容器为空时,removeFirst方法会抛出异常。下面给出pollFirst方法代码。

public E pollFirst() {
        int h = head;
        @SuppressWarnings("unchecked")
        E result = (E) elements[h];
        // Element is null if deque empty
        if (result == null)
            return null;
        elements[h] = null;     // Must null out slot
        head = (h + 1) & (elements.length - 1);
        return result;
    }

如果deque是空的,elment是null,调用elementAt方法。该方法其实就是在内部数组中根据下标,获取了一下元素。

removeLast

public E removeLast() {
        E x = pollLast();
        if (x == null)
            throw new NoSuchElementException();
        return x;
    }
public E pollLast() {
        int t = (tail - 1) & (elements.length - 1);
        @SuppressWarnings("unchecked")
        E result = (E) elements[t];
        if (result == null)
            return null;
        elements[t] = null;
        tail = t;
        return result;
    }

removeLast方法调用了pollLast方法,删除并返回当前末端的元素。当容器为空时,抛出异常。

二、PriortyQueue

简介

PriorityQueue是优先级队列,其底层通过堆实现,具体说是通过完全二叉树实现的小顶堆,排序采用自然排序或者通过提供的Comparator比较器去进行排序。不允许放入null元素。

成员变量

private static final int DEFAULT_INITIAL_CAPACITY = 11;
transient Object[] queue;
private int size = 0;
private final Comparator<? super E> comparator;
transient int modCount = 0;
private static final long serialVersionUID = -7720805057305804111L;

PriorityQueue 使用数组 queue 来存储元素,默认初始容量是 11,最大容量是 Integer.MAX_VALUE - 8。comparator 若为 null,则按照元素的自然序来排列。modCount 用来提供 fail-fast 机制。

构造函数

public PriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }
public PriorityQueue(int initialCapacity) {
        this(initialCapacity, null);
    }
public PriorityQueue(Comparator<? super E> comparator) {
        this(DEFAULT_INITIAL_CAPACITY, comparator);
    }
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) {
        if (c instanceof SortedSet<?>) {
            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
            this.comparator = (Comparator<? super E>) ss.comparator();
            initElementsFromCollection(ss);
        }
        else if (c instanceof PriorityQueue<?>) {
            PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
            this.comparator = (Comparator<? super E>) pq.comparator();
            initFromPriorityQueue(pq);
        }
        else {
            this.comparator = null;
            initFromCollection(c);
        }
    }
 public PriorityQueue(PriorityQueue<? extends E> c) {
        this.comparator = (Comparator<? super E>) c.comparator();
        initFromPriorityQueue(c);
    }
public PriorityQueue(SortedSet<? extends E> c) {
        this.comparator = (Comparator<? super E>) c.comparator();
        initElementsFromCollection(c);
    }

PriorityQueue 的构造函数有 7 个,可以分为两类,提供初始元素和不提供初始元素,有比较器和没有比较器。PriorityQueue中的对象要么有自己单独的比较器,要么对象所在类实现Comparable接口,需要保证当前对象可比较。

add

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;
    }

先看传入参数是否合法,然后判断是否需要扩容,需要扩容调用grow方法来进行扩容。如果队列为空,直接添加进队列,如果队列不为空,调用siftUp函数,代码如下:

private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }

传入i为size,e为添加的值。如果传入比较器,按比较器比较进行添加,否则按自然顺序进行排序。

remove

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

首先调用IndexOf()找这个元素在数组中的位置,保证元素不为空, 调用removeAt(i)函数删除指定位置元素。

 private E removeAt(int i) {
        // assert i >= 0 && i < size;
        modCount++;
        int s = --size;
        if (s == i) // removed last element
            queue[i] = null;
        else {
            E moved = (E) queue[s];
            queue[s] = null;
            siftDown(i, moved);
            if (queue[i] == moved) {
                siftUp(i, moved);
                if (queue[i] != moved)
                    return moved;
            }
        }
        return null;
    }

先size–,赋值给s,如果s等于i,删除的就是最后一个位置,直接置为空就删除掉了,反之要进行调整,将s位置置为空,然后用siftDown从上往下进行调整。如果所要删除的一个元素等于size-1的一个值,在进行从下往上siftUp。如果调整了以后不等于size-1的值,直接返回回去size-1的值。

 private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }

该方法的作用是从k指定的位置开始,将x逐层向下与当前点的左右孩子中较小的那个交换,直到x小于或等于左右孩子中的任何一个为止。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值