什么是队列

队列是一种特殊的线性表,只能在头尾两端进行操作。

  • 队尾(rear):只能在队尾添加元素,一般叫enQueue,入队
  • 队头(front):只能在队头移除元素,一般叫deQueue,出队
  • 先进先出的原则,First in First out。

image.png

队列的接口设计

  • int size();// 元素的数量
  • boolean isEmpty();//是否是空
  • void enQueue(E element);//入队
  • E deQueue();//出队
  • E front();//查看队头元素
  • void clear();//清空元素

队列可以使用动态数组或链表实现,优先使用**双向链表实现,队列主要是在头尾**进行操作元素

双端队列(Deque,double ended queue)

双端队列能在头尾两端添加、删除元素

双端队列接口设计

  • int size();// 元素的数量
  • boolean isEmpty();//是否是空
  • void clear();//清空元素
  • void enQueueFront(E element);//从队头入队
  • void enQueueRear(E element);//从队尾入队
  • E deQueueFront();//从队头出队
  • E deQueueRear();//从队尾出队
  • E front();//查看队头元素
  • E rear();//查看队尾元素

java.util.LinkedList 是双端队列

  1. public class LinkedList<E>
  2. extends AbstractSequentialList<E>
  3. implements List<E>, Deque<E>, Cloneable, java.io.Serializable{}
  4. public interface Deque<E> extends Queue<E> {}

循环队列

其实队列的底层也可以使用动态数组实现,并且各项接口也可以优化到O(1)的时间复杂度,这个数组实现并且优化后的队列叫做循环队列。
image.png

成员设计

  1. public class CircleQueue<E> extends CustQueue<E> {
  2. private E[] array;
  3. /**
  4. * 队列的元素个数
  5. */
  6. private int size;
  7. /**
  8. * 队头元素的位置index
  9. */
  10. private int front;
  11. }

入队(从队尾入队)

  1. /**
  2. * 入队(从队尾位置入队)
  3. */
  4. @Override
  5. public void enQueue(E element) {
  6. //保证容量
  7. ensureCapacity(size + 1);
  8. array[realIndex(size)] = element;
  9. size++;
  10. }

出队(从队头出队)

  1. /**
  2. * 出队(从队头位置出队)
  3. *
  4. * @return
  5. */
  6. @Override
  7. public E deQueue() {
  8. E e = array[front];
  9. array[front] = null;
  10. front = realIndex(1);
  11. size--;
  12. return e;
  13. }

获取 index 对应的真实索引

  1. /**
  2. * 获取 index 对应的真实索引
  3. *
  4. * @param index
  5. * @return
  6. */
  7. private int realIndex(int index) {
  8. //return (front + index) % array.length;
  9. //(n%m) = (n>m)?(n-m):n;
  10. index += front;
  11. return index >= array.length ? (index - array.length) : index;
  12. }

扩容

  1. /**
  2. * 保证有capacity个容量
  3. *
  4. * @param capacity
  5. */
  6. private void ensureCapacity(int capacity) {
  7. int oldCapacity = array.length;
  8. if (capacity <= oldCapacity) {
  9. return;
  10. }
  11. //扩1.5倍
  12. int newCapacity = oldCapacity + (oldCapacity >> 1);
  13. E[] newArray = (E[]) new Object[newCapacity];
  14. int count = size;
  15. for (int i = 0; i < count; i++) {
  16. newArray[i] = array[realIndex(i)];
  17. }
  18. array = newArray;
  19. front = 0;
  20. }

%模运算优化

  1. //(front + index) % array.length;
  2. // n>=0,m>0,n<2m
  3. // front = 9 , index =9
  4. int n = 18;
  5. //m = array.length =10
  6. int m = 10;
  7. System.out.println(n % m);// 结果是8,n-m
  8. //front=2 ,index =3,m = array.length =7
  9. n = 5;
  10. m = 7;
  11. System.out.println(n % m);//结果是5,n
  12. (n%m) = (n>m)?(n-m):n;

image.png

循环双端队列

可以在两端进行添加、删除操作的循环队列。