Queue接口下的集合

ArrayDeque

特点

底层数据结构:数组
Collection接口下:存储单值

继承的接口

public class ArrayDeque<E> extends AbstractCollection<E>
                           implements Deque<E>, Cloneable, Serializable
  1. Deque:双端队列接口。
  2. Cloneable:可以使用clone方法。
  3. Serializable:可序列化。

双端队列可以实现普通队列和栈的功能。

使用

双端队列

添加和删除元素分别都可以从头部和尾部进行。

  1. 添加元素
addFirst(E e) //头插,如果e为空返回异常
offerFirst(E e) //头插并返回是否添加成功,如果e为空返回异常

addLast(E e) //尾插,如果e为空返回异常
offerLast(E e) //尾插并返回是否添加成功,如果e为空返回异常
  1. 删除元素
removeFirst() //头删,并返回删除元素的值,如果为空则抛出异常
pollFirst() //头删,并返回删除元素的值,如果为空则返回null

removeLast() //尾删,并返回删除元素的值,如果为空则抛出异常
pollLast()//尾删,并返回删除元素的值,如果为空则返回null

removeFirstOccurrence(Object o) //删除第一次出现的指定元素
removeLastOccurrence(Object o) //删除最后一次出现的指定元素
  1. 获取元素
getFirst() //获取第一个元素,如果为空则抛出异常
getLast() //获取最后一个元素,如果为空则抛出异常

双端队列作普通队列

add(E e) //尾插
offer(E e) //尾插并返回是否成功
remove() //头删,并返回删除元素的值,如果为空则抛出异常,底层调用的是removeFirst()
poll() //头删,并返回删除元素的值,如果为空则返回null,底层调用的是pollFirst()
element() //获取第一个元素,如果为空则抛出异常
peek() //获取最后一个元素,如果为空则抛出异常

双端队列作栈

push(E e) //栈顶添加一个元素
pop() //移除栈顶元素,如果为空则抛出异常

其他

size() //获取元素个数
isEmpty() //判断队列是否为空
iterator() //迭代器,从前向后迭代
descendingIterator() //迭代器,从后向前迭代
contain(Object o) //判断队列中是否存在该元素
toArray() //转成数组
clear() //清空队列、
clone() //克隆一个新的队列

源码分析

构造器

public ArrayDeque() {
    elements = (E[]) new Object[16];//默认容量为16
}

public ArrayDeque(int numElements) {
    allocateElements(numElements);//将容量向上取2的幂
}

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

add相关

其他添加方法都调用这两个函数

public void addFirst(E e) {
    if (e == null)
        throw new NullPointerException();
    //队头添加,比(head-1)%elemrnts.length效率更高
    elements[head = (head - 1) & (elements.length - 1)] = e;
    if (head == tail)
        doubleCapacity();
}

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

doubleCapacity方法

private void doubleCapacity() {
    assert head == tail;
    int p = head;
    int n = elements.length;
    int r = n - p; // number of elements to the right of p
    int newCapacity = n << 1;//2倍扩容
    if (newCapacity < 0)
        throw new IllegalStateException("Sorry, deque too big");
    Object[] a = new Object[newCapacity];
    System.arraycopy(elements, p, a, 0, r);
    System.arraycopy(elements, 0, a, r, p);
    elements = (E[])a;
    head = 0;
    tail = n;
}

示意图
在这里插入图片描述

poll相关

其他删除方法都调用这两个函数

public E pollFirst() {
    int h = head;
    E result = elements[h]; //保存删除元素
    if (result == null)
        return null;
    elements[h] = null;//将数组中删除元素置空
    head = (h + 1) & (elements.length - 1);//循环
    return result;
}

public E pollLast() {
    int t = (tail - 1) & (elements.length - 1);//循环
    E result = elements[t];//保存删除元素
    if (result == null)
        return null;
    elements[t] = null;//将数组中删除元素置空
    tail = t;
    return result;
}

get相关

其他获取方法都调用这两个函数

public E getFirst() {
    E x = elements[head];
    if (x == null)
        throw new NoSuchElementException();
    return x;
}

public E getLast() {
    E x = elements[(tail - 1) & (elements.length - 1)];
    if (x == null)
        throw new NoSuchElementException();
    return x;
}

LinkedList

特点

LinkedList可作双端队列使用。效率没有ArrayDeque高。

继承的接口

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

Deque:可作双端队列使用,添加/删除元素都可以从头部或者尾部进行。

使用

当作链表操作

//添加
add(E e); //尾插
add(int index, E element); //随机插入
//删除
remove(E o); //删除指定元素
remove(int index) //删除指定下标元素
//获取
get(int index); //获取指定下标元素
//修改
set(int index , E element); //修改指定下标元素

作双端队列使用

//添加
addFirst(E e); //头插,特有方法
addLast(E e); //尾插,特有方法
offerFirst(E e); //头插,返回是否成功
offerLast(E e); //尾插,并返回是否成功
//删除
removeFirst(E e); //头删并获取
removeLast(E e); //尾删并获取
pollFirst(); //头删
pollLast(); //尾删
removeFirstOccurrence(Object o); //删除第一次出现的指定元素
removeLastOccurrence(Object o); //删除最后一次出现的指定元素
//获取
getFirst(); //获取第一个元素,为空则抛异常
getLast(); //获取最后一个元素,为空则抛异常
peekFirst(): //获取第一个元素,为空则返回空
peekLast(); //获取最后一个元素,为空则返回空

作普通队列使用

add(E e) //尾插
offer(E e) //尾插并返回是否成功
remove() //头删,并返回删除元素的值,如果为空则抛出异常,底层调用的是removeFirst()
poll() //头删,并返回删除元素的值,如果为空则返回null,底层调用的是pollFirst()
element() //获取第一个元素,如果为空则抛出异常
peek() //获取最后一个元素,如果为空则抛出异常

作栈使用

push(E e) //栈顶添加一个元素
pop() //移除栈顶元素,如果为空则抛出异常

其他

size() //获取元素个数
iterator() //迭代器,从前向后迭代
contain(Object o) //判断队列中是否存在该元素
toArray() //转成数组
clear() //清空队列
clone() //克隆一个新的队列

源码分析

PriorityQueue

特点

传统队列具有先入先出的特点,先添加的元素先弹出,先添加的元素优先级高。

优先级队列的先入先出:提供一个优先级比较原则,优先级队列根据这个原则,谁最小优先级最高,优先级高的先弹出。

继承的接口

public class PriorityQueue<E> extends AbstractQueue<E>
    implements java.io.Serializable {
  1. Queue:队列接口,具有队列先入先出的特点。
  2. Serializable:可序列化。
  3. Iterator:迭代器,可以从前向后遍历。

使用

常用方法

//添加一个指定元素,如果e为空则返回空指针异常
boolean offer(E e)

//添加一个指定元素,直接调用offer方法
boolean add()

//删除一个指定元素,如果e为空则返回false
boolean remove(Object o)

//删除队头,如果没有队头则返回null
E poll()

//获取队头元素,如果没有队头则返回null
E peek()

//获取队头元素,如果没有队头则抛出异常
E element()

源码分析

构造器

//无参构造,默认容量为11
public PriorityQueue() {
    this(DEFAULT_INITIAL_CAPACITY, null);
}
//有参构造指定初始容量
public PriorityQueue(int initialCapacity) {
    this(initialCapacity, null);
}

//双参构造,初始容量和外比较器
public PriorityQueue(int initialCapacity,
                     Comparator<? super E> comparator) {
    if (initialCapacity < 1)
        throw new IllegalArgumentException();
    this.queue = new Object[initialCapacity];
    this.comparator = comparator;
}
//有参构造,外比较器
@SuppressWarnings("unchecked")
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);
    }
}

offer方法

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

siftUp方法

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];
        //如果x比父节点大,满足小根堆,退出循环
        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;
}

grow方法

private void grow(int minCapacity) {
    int oldCapacity = queue.length;
    // 如果初始容量小于6,2倍+2扩容,否则1.5倍扩容
    int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                                     (oldCapacity + 2) :
                                     (oldCapacity >> 1));
    // 容量溢出处理
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    queue = Arrays.copyOf(queue, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

poll方法

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

siftDown

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;
    //直到遇到叶子节点,循环退出
    while (k < half) {
        int child = (k << 1) + 1; //左孩子下标
        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;
}

remove方法

public boolean remove(Object o) {
    int i = indexOf(o);//找出该元素下标
    if (i == -1)
        return false;
    else {
        removeAt(i);
        return true;
    }
}

private E removeAt(int i) {
    assert i >= 0 && i < size;
    modCount++;
    int s = --size;
    if (s == i) // 移除最后一个节点
        queue[i] = null;
    else {
        E moved = (E) queue[s];// 记录最后一个元素
        queue[s] = null;// 将最后一个元素置空
        siftDown(i, moved);  // 将最后一个元素放在i的位置,向下调整
        //向下调整如果执行,那么此时i位置一定比当前子树的根小,满足小根堆
        //如果向下调整没有执行,则向上调整
        //因为当左右分支差距过大时,无法确定最后一个节点是否比当前子树的根小
        if (queue[i] == moved) {
            siftUp(i, moved);//向上调整
            if (queue[i] != moved)
                return moved;
        }
    }
    return null;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值