目录
队列的简介:
- 队列是一种线性结构
- 相比数组,栈对应的操作是数组的子集
- 只能从一端添加元素,也只能从一端取出元素
队列的图示:
队列的实现:
代码实现:
public class ArrayQueue<E> implements LearnQueue<E> {
private LearnArray<E> array;
public ArrayQueue(int capacity) {
array = new LearnArray<>(capacity);
}
public ArrayQueue() {
array = new LearnArray<>();
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
public int getCapacity() {
return array.getCapacity();
}
//向队列中添加元素
@Override
public void enqueue(E e) {
array.addLast(e);
}
//从队列中移除元素
@Override
public E dequeue() {
return array.removeFirst();
}
@Override
public E getFront() {
return array.getFirst();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Queue:");
sb.append("front [");
for (int i = 0; i < array.getSize(); i++) {
sb.append(array.get(i));
if (i != array.getSize() - 1) {
sb.append(", ");
}
}
sb.append("] tail");
return sb.toString();
}
public static void main(String[] args) {
ArrayQueue<Integer> arrayQueue = new ArrayQueue<>();
for (int i = 0; i < 10; i++) {
arrayQueue.enqueue(i);
System.out.println(arrayQueue);
if (i % 3 == 2){
arrayQueue.dequeue();
System.out.println(arrayQueue);
}
}
}
}
数组队列的复杂度分析:
如果有一百万个元素,那么出队的操作将会非常慢,那么,有没有一种队列,让出队的时间复杂度也是O(1)呢,那就是循环队列!
循环队列图解:
循环的主要实现就是通过 (tail+1)%capacity == front来实现的,取余可以让队列完美实现循环。例如,当front=0,tail=7时,
(tail+1)%capacity==front刚好也是成立的。
循环队列代码:
/**
* 循环队列
*
* @param <E>
*/
public class LoopQueue<E> implements Queue<E> {
private E[] data;
// 指向队首元素所在的索引
private int front;
// 指向 队尾元素的下一个位置所在的索引
private int tail;
private int size;
public LoopQueue(int capacity) {
//对于循环队列来说,要有意识的多浪费一个容量
data = (E[]) new Object[capacity + 1];
front = 0;
tail = 0;
size = 0;
}
public LoopQueue() {
this(10);
}
public int getCapacity() {
// 要去掉多余的一个容量
return data.length - 1;
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return front == tail;
}
@Override
public void enqueue(E e) {
// 队列满了
if ((tail + 1) % data.length == front) {
resize(getCapacity() * 2);
}
data[tail] = e;
tail = (tail + 1) % data.length;
size++;
}
@Override
public E dequeue() {
if (isEmpty()) {
throw new IllegalArgumentException("Cannot dequeue from an empty queue.");
}
E ret = data[front];
data[front] = null;
front = (front + 1) % data.length;
size--;
// 缩容操作
if (size == getCapacity() / 4 && getCapacity() / 2 != 0) {
resize(getCapacity()/2);
}
return ret;
}
@Override
public E getFront() {
if (isEmpty()) {
throw new IllegalArgumentException("Cannot dequeue from an empty queue.");
}
return data[front];
}
private void resize(int newCapacity) {
E[] newData = (E[]) new Object[newCapacity + 1];
for (int i = 0; i < size; i++) {
// 扩容后,newData中的值肯定希望能够从队首开始排列,但是在
// data中数据可能发生偏移了,偏移量是front,所以要做一下处理
newData[i] = data[(i + front) % data.length];
}
data = newData;
front = 0;
tail = size;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("Queue: size = %d , capacity = %d\n", size, getCapacity()));
sb.append("front [");
for (int i = front; i != tail; i = (i + 1) % data.length) {
sb.append(data[i]);
// 当前元素不是最后一个元素
if ((i + 1) % data.length != tail) {
sb.append(", ");
}
}
sb.append("] tail");
return sb.toString();
}
public static void main(String[] args) {
LoopQueue<Integer> queue = new LoopQueue<>();
for (int i = 0; i < 10; i++) {
queue.enqueue(i);
System.out.println(queue);
//每插入三个元素,移除队首元素
if (i % 3 == 2) {
queue.dequeue();
System.out.println(queue);
}
}
}
}
循环队列复杂度分析:
数组队列和循环队列性能比较:
public class Test {
//测试使用q运行opCount个enqueue和dequeue操作所需要的时间,单位:秒
private static double testQueue(LearnQueue<Integer> queue, int opCount) {
long startTime = System.nanoTime();
Random random = new Random();
for (int i = 0; i < opCount; i++) {
queue.enqueue(random.nextInt(Integer.MAX_VALUE));
}
for (int i = 0; i < opCount; i++) {
queue.dequeue();
}
long endTime = System.nanoTime();
return (endTime - startTime) / 1000000000.0;
}
public static void main(String[] args) {
int opCount = 100000;
ArrayQueue<Integer> arrayQueue = new ArrayQueue<>();
double time1 = testQueue(arrayQueue, opCount);
System.out.println("ArrayQueue, time: " + time1 + "s");
LoopQueue<Integer> loopQueue = new LoopQueue<>();
double time2 = testQueue(loopQueue, opCount);
System.out.println("LoopQueue, time: " + time2 + "s");
}
}
对比结果:
ArrayQueue, time: 3.472903058s
LoopQueue, time: 0.01233089s
可以看到,性能相差三百多倍。