队列跟栈一样是一种受限型线性表数据结构,栈只允许入栈push和出栈pop,队列则只允许入队enqueue,出队dequeue。任何数据结构的存在和产生都有对应的应用场景和待解决问题,由队列的特点可以知道等待或者限制的处理队列是一个好的选择。
1 什么队列?
队列可以类比现实世界中的排队,先来的先处理,后来的后处理,针对数据存储结构就是先进先出,后进后出。既然是排队,常见的应用场景那肯定是面对稀缺资源时候的调度
2 队列的实现
2.1 简单的队列实现
根据队列的特点需要知道队首在哪,队尾在哪,队列中有多少数据,以及存储的这些数据。
队列的实现来说,关键在于在队满和队空的时候对队首和队尾的操作。
不考虑扩容和缩容下的简单实现。
public class SimpleQueue {
private String[] items;
private int head;
private int tail;
private int capacity;
public SimpleQueue(int capacity) {
this.capacity = capacity;
this.items = new String[capacity];
this.head = 0;
this.tail = 0;
}
public boolean enQueue(String val) {
if (tail == capacity) {
if (head == 0) {
return false;
}
int size = tail - head;
for (int i = 0; i < size; i++) {
items[i] = items[head++];
}
head = 0;
tail = size;
}
items[tail++] = val;
return true;
}
public String deQueue() {
if (tail == head) {
return null;
}
return items[head++];
}
}
2.2 循环队列实现
循环队列添加一个size用于辅助判断当前队空还是队满,如果不加size的话会相对麻烦。
public class CycleQueue {
private int head;
private int tail;
private String[] items;
private int capacity;
private int size;
public CycleQueue(int capacity) {
this.capacity = capacity;
head = 0;
tail = 0;
items = new String[capacity];
}
public boolean enQueue(String val) {
if (size == capacity) {
System.out.println("队列已满");
return false;
}
if (tail == capacity - 1) {
items[tail] = val;
tail = 0;
} else {
items[tail++] = val;
}
size++;
return true;
}
public String deQueue() {
if (size == 0) {
System.out.println("队列是空的");
return null;
}
size--;
if (head == capacity - 1) {
String current = items[head];
head = 0;
return current;
} else {
return items[head++];
}
}
}
3. 队列的应用
队列的出队入队特性可以很好看控制资源的流入和流出所以在多线程情况下应用较为广泛。
阻塞队列:线程不安全,在队列基础上加上阻塞操作。
并发队列:线程安全,其实就是在入队和出队上加上锁,锁的粒度决定了效率
无界队列:底层是链表,缺点,基本无限,可能会影响取出过程的效率
有界队列:底层是数组,可能不够用
优先队列、双端队列等应用