定义
如何理解“队列”
- 队列是一个操作受限的线性表
- 具有先进先出的性质
- 跟「栈」一样,分为顺序队列和链式队列
用数组实现的顺序队列和用链表实现的链式队列
- 主要要关注队满和队空条件
- 线性队列 > 队满:tail == n | 队空(没有数据):head == tail
- 链式队列 > 队满:无界 | 队空:head.next = tail
- 线性队列的数据搬迁:当队满时,可以进行数据搬迁来利用空余的数组空间
动态扩容
- 跟顺序链表一样,顺序队列也可支持动态扩容
- 如果在每次出队时,进行数据搬迁,则出队的时间复杂度就会变为 O(n)。
- 为了避免上述情况,只需要在入队空间不足时,进行数据搬迁即可
使用循环队列避免数据搬移操作
扩容时的数据搬迁操作,会导致 O(n) 的时间复杂度
- 循环队列将数组看成是一个「环」,主要关注其中的队满条件
- 对满:(head + 1) % n == tail
- 队空:head == tail
特殊队列:阻塞队列和并发队列
- 阻塞队列:典型的生产者 - 消费者模型。
- 就是在队列为空的时候,从队头取数据会被阻塞。因为此时还没有数据可取,直到队列中有了数据才能返回;如果队列已经满了,那么插入数据的操作就会被阻塞,直到队列中有空闲位置后再插入数据,然后再返回。
- 并发队列:多线程情况下,线程安全的队列
实现
顺序队列
public class ArrayQueue implements Queue {
private final String[] queue;
private final int capacity;
private int head;
private int tail;
public ArrayQueue(int capacity) {
this.capacity = capacity;
queue = new String[capacity];
}
@Override
public boolean enqueue(String item) {
if (capacity == tail) return false;
queue[tail++] = item;
return true;
}
@Override
public String dequeue() {
if (head == tail) return null;
return queue[head++];
}
public static void main(String[] args) {
ArrayQueue queue = new ArrayQueue(5);
Assert.assertNull(queue.dequeue());
queue.enqueue("item1");
queue.enqueue("item2");
Assert.assertEquals("item1", queue.dequeue());
Assert.assertEquals("item2", queue.dequeue());
Assert.assertNull(queue.dequeue());
}
}
链式队列
public class LinkedQueue implements Queue {
private ListNode tail = null;
private ListNode head = null;
private int size;
@Override
public boolean enqueue(String item) {
ListNode newNode = new ListNode(item);
if (size == 0) {
head = newNode;
tail = newNode;
} else {
this.tail.next = newNode;
this.tail = this.tail.next;
}
size++;
return true;
}
@Override
public String dequeue() {
if (size == 0) return null;
String val = head.val;
head = head.next;
size--;
return val;
}
public static void main(String[] args) {
LinkedQueue queue = new LinkedQueue();
Assert.assertNull(queue.dequeue());
Assert.assertTrue(queue.enqueue("item1"));
Assert.assertTrue(queue.enqueue("item2"));
Assert.assertEquals("item1", queue.dequeue());
Assert.assertEquals("item2", queue.dequeue());
Assert.assertNull(queue.dequeue());
}
}
class ListNode {
String val;
ListNode next;
ListNode(String x) {
val = x;
}
}
动态扩容
public class DynamicArrayQueue implements Queue {
private final String[] queue;
private final int capacity;
private int head;
private int tail;
public DynamicArrayQueue(int capacity) {
this.capacity = capacity;
queue = new String[capacity];
}
/**
* 会在容量不足时,进行数据搬迁
*/
@Override
public boolean enqueue(String item) {
if (capacity == tail) {
//队列是满的,没法搬迁
if (head == 0) return false;
for (int i = head; i < tail; i++) {
queue[i - head] = queue[head];
}
//tail = 长度 head = 队头
tail = tail - head;
head = 0;
}
queue[tail++] = item;
return true;
}
@Override
public String dequeue() {
if (head == tail) return null;
return queue[head++];
}
public static void main(String[] args) {
Queue queue = new DynamicArrayQueue(3);
Assert.assertNull(queue.dequeue());
Assert.assertTrue(queue.enqueue("item1"));
Assert.assertEquals("item1", queue.dequeue());
Assert.assertTrue(queue.enqueue("item2"));
Assert.assertEquals("item2", queue.dequeue());
Assert.assertTrue(queue.enqueue("item3"));
Assert.assertEquals("item3", queue.dequeue());
Assert.assertTrue(queue.enqueue("item4"));
Assert.assertEquals("item4", queue.dequeue());
}
}
循环队列
public class CycleArrayQueue implements Queue {
private final String[] queue;
private final int capacity;
private int head;
private int tail;
public CycleArrayQueue(int capacity) {
this.capacity = capacity;
queue = new String[capacity];
}
@Override
public boolean enqueue(String item) {
//队满条件 (head + 1) % n == tail
if ((head + 1) % capacity == tail) return false;
queue[tail] = item;
tail = (tail + 1) % capacity;
return true;
}
@Override
public String dequeue() {
//队空 head == tail
if (head == tail) return null;
String value = queue[head];
head = (head + 1) % capacity;
return value;
}
public static void main(String[] args) {
CycleArrayQueue queue = new CycleArrayQueue(5);
Assert.assertNull(queue.dequeue());
Assert.assertTrue(queue.enqueue("item1"));
Assert.assertEquals("item1", queue.dequeue());
Assert.assertTrue(queue.enqueue("item2"));
Assert.assertEquals("item2", queue.dequeue());
Assert.assertTrue(queue.enqueue("item3"));
Assert.assertEquals("item3", queue.dequeue());
Assert.assertTrue(queue.enqueue("item4"));
Assert.assertEquals("item4", queue.dequeue());
}
}