1. 概述
-
- 队列对应的操作是数组的子集
- 只能从一端(队尾)添加元素,只能从另一端(队首)删除元素
- 先进先出(FIFO:First In First Out)
2. 队列的实现
队列的接口定义:
代码实现:
package com.ytuan.queue; public interface Queue<E> { public void enqueue(E e); public E dequeue(); public boolean isEmpty(); public int getSize(); public E getFront(); }
数组队列:
在这里会使用之前实现的动态数组,参考地址:https://www.cnblogs.com/ytuan996/p/10692548.html
代码实现:
package com.ytuan.queue; import com.ytuan.array.Array; public class ArrayQueue<E> implements Queue<E> { private Array<E> array; public ArrayQueue(int capacity) { array = new Array<>(capacity); } public ArrayQueue() { array = new Array<E>(); } @Override public void enqueue(E e) { array.addLast(e); } @Override public E dequeue() { return array.removeFirst(); } @Override public boolean isEmpty() { return array.isEmpty(); } @Override public int getSize() { return array.getSize(); } @Override public String toString() { StringBuffer res = new StringBuffer(); res.append(String.format("Queue size = %d, capacity = %d. ", array.getSize(), array.getCapacity())); res.append("front ["); for (int i = 0; i < array.getSize(); i++) { res.append(array.get(i)); if (i != array.getSize() - 1) res.append(','); } res.append("] end"); return new String(res); } @Override public E getFront() { return array.getFirst(); } }
循环队列:
在数组队列的实现中,对于dequeue(出队)的时间复杂度是O(n)级别的,而循环队列是解决这一问题的方案。它使用两个之指针分别表示队列的队首和队尾,在整个数组中循环改变,多使用一个空间来维护这两个指针的关系。示意如图:
代码实现:
package com.ytuan.queue; public class LoopQueue<E> implements Queue<E> { private E[] data; private int front, tail; private int size; // 元素个数,可以省略,使用front, tail计算得到。扩展部分 public LoopQueue(int capacity) { data = (E[]) new Object[capacity + 1]; front = 0; tail = 0; size = 0; } public LoopQueue() { this(10); } @Override public void enqueue(E e) { if (tail + 1 == front) resize(getCapacity() * 2); data[tail] = e; tail = (tail + 1) % data.length; size++; } private void resize(int newCapacity) { E newData[] = (E[]) new Object[newCapacity + 1]; for (int i = 0; i < size; i++) { newData[i] = data[(i + front) % data.length]; } data = newData; front = 0; tail = size; } @Override public String toString() { StringBuffer res = new StringBuffer(); res.append(String.format("Queue size = %d, capacity = %d. ", getSize(), getCapacity())); res.append("front ["); for (int i = front; i != tail; i = (i + 1) % data.length) { res.append(data[i % data.length]); if ((i + 1) % data.length != tail) res.append(','); } res.append("] tail"); return new String(res); } @Override public E dequeue() { if (isEmpty()) throw new IllegalArgumentException("can not dequeue form an Empty Queue"); E res = data[front]; data[front] = null; front = (front + 1) % data.length; size--; if (size == getCapacity() / 4 && getCapacity() / 2 != 0) resize(getCapacity() / 2); return res; } @Override public boolean isEmpty() { return size == 0; } @Override public int getSize() { return size; } public int getCapacity() { return data.length - 1; } @Override public E getFront() { if (isEmpty()) throw new IllegalArgumentException("no element to access!"); return data[front]; } }