数据结构(四)队列

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/www851903307/article/details/82828457

一、基本概念

1、特点:

  • 在队列头部进行删除,在队列的尾部进行插入操作

2、主要实现:

  • 使用循环数组
  • 使用链表
    在这里插入图片描述
    3、关系图:
    在这里插入图片描述

二、Queue

public interface Queue<E> extends Collection<E> {
  //添加	
  boolean add(E var1);
  //添加
  boolean offer(E var1);
  //移除
  E remove();
  //移除
  E poll();
  //获取元素
  E element();
  //获取
  E peek();
}

一般peek、poll、offer方法跟其他类似方法的区别在于为空会返回null

三、Deque

1、特点:

  • 双端队列:Deque是一种具有队列和栈的性质的数据结构,插入和删除操作可以在表的两端进行。
    LinkedList实现了Deque接口,可以在两端进行插入和删除操作。

2、接口源码:

public interface Deque<E> extends Queue<E> {
    //将元素插入队列
	boolean add(E e);
	//将元素插入队列,与add相比,在容量受限时应该使用这个
	boolean offer(E e);
	//将队首的元素删除,队列为空则抛出异常
	E remove();
	//将队首的元素删除,队列为空则返回null
	E poll();
	//获取队首元素,但不移除,队列为空则抛出异常
	E element();
	//获取队首元素,但不移除,队列为空则返回null
	E peek();
	...
}

提供了在两端移除、添加的相关方法

四、ArrayDeque

双端队列

  • ArrayDeque通过循环数组的方式实现循环队列,容量为2的次幂。
  • 作为Stack,因为其非线程安全所以效率高于java.util.Stack,而作为队列,因为其不需要结点支持所以更快。

1、变量:

public class ArrayDeque<E> extends AbstractCollection<E>
        implements Deque<E>, Cloneable, Serializable {
    //元素存储为数组
    transient Object[] elements;
    //头部元素索引
    transient int head;
    //队部元素索引
    transient int tail;
    //最小容量
    private static final int MIN_INITIAL_CAPACITY = 8;
    ...
}

2、构造:

/**
 * 无参构造,默认大小为16
 */
public ArrayDeque() {
    elements = new Object[16];
}
/**
 * @param numElements 初始容量
 */
public ArrayDeque(int numElements) {
    allocateElements(numElements);
}
/**
 * 传入一个集合
 * @param c
 */
public ArrayDeque(Collection<? extends E> c) {
	//获取初始容量,并创建数组
    allocateElements(c.size());
	//添加元素
    addAll(c);
}

获取初始容量,并创建数组

private void allocateElements(int numElements) {
    int initialCapacity = MIN_INITIAL_CAPACITY;
    //如果传入的容量>=MIN_INITIAL_CAPACITY
    if (numElements >= initialCapacity) {
	    //通过右移和位或运算得到大于numElements的2^n个容量
        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];
}

3、添加元素

添加元素都是从队列的尾部添加,如果调用addFirst,就是将索引为0作为队首,需要从length-1的位置(队尾)开始添加。如果addLast,则索引为0作为队尾。

public void addFirst(E e) {
    if (e == null)
        throw new NullPointerException();
    //如果elements.length为8,最终head的索引为7,然后赋值
    elements[head = (head - 1) & (elements.length - 1)] = e;
    //进行扩容
    if (head == tail)
        doubleCapacity();
}
//如果将1-8的元素依次通过addFirst添加到队列中,此时head是从7到0,最终的顺序为[8,7,6,5,4,3,2,1]。

public void addLast(E e) {
    if (e == null)
        throw new NullPointerException();
    //队尾赋值,首次添加元素时tail为0
    elements[tail] = e;
	//将tail后移一位
    if ( (tail = (tail + 1) & (elements.length - 1)) == head)
        doubleCapacity();
}
//如果将1-8的元素依次通过addLast添加到队列中,此时tail从1到8,最终的顺序为[1,2,3,4,5,6,7,8]

//将容量扩大到2倍,然后元素复制到新数组
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;
     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 = a;
     head = 0;
     tail = n;
 }

4、删除元素:

删除元素时在队首删除,removeFirst时队首在前(索引为head)开始删,removeLast时队首在后(索引为tail)处开始删。

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

public E removeLast() {
    E x = pollLast();
    if (x == null)
        throw new NoSuchElementException();
    return x;
}

public E pollFirst() {
    final Object[] elements = this.elements;
    final int h = head;
    @SuppressWarnings("unchecked")
    //获取head元素
    E result = (E) elements[h];
    // Element is null if deque empty
    if (result != null) {
	    //head的元素置空,将head向后移动一位
        elements[h] = null; // Must null out slot
        head = (h + 1) & (elements.length - 1);
    }
    return result;
}

public E pollLast() {
    final Object[] elements = this.elements;
    //通过&运算获取队首元素索引(如果tail为2,队首索引t为1)
    final int t = (tail - 1) & (elements.length - 1);
    @SuppressWarnings("unchecked")
    E result = (E) elements[t];
    if (result != null) {
	    //删除最后一个元素,将tail向前移动一位
        elements[t] = null;
        tail = t;
    }
    return result;
}

5、获取元素:

public E getFirst() {
    @SuppressWarnings("unchecked")
    E result = (E) elements[head];
    if (result == null)
        throw new NoSuchElementException();
    return result;
}

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

猜你喜欢

转载自blog.csdn.net/www851903307/article/details/82828457