队列:先进者先出;操作受限的线性表数据结构
最基本的两个操作,入队和出队
顺序队列和链式队列
队列也可以用数组来实现,也可以用链表来实现。用数组实现的栈叫顺序栈,用链表实现的栈叫链式栈。
对于栈来说,只需要一个栈顶指针就可以了,但队列需要两个指针:一个是head指针,指向对头;一个tail指针,指向队尾。
用数组实现队列
// 用数组实现的队列
public class ArrayQueue {
// 数组:items,数组大小:n
private String[] items;
private int n = 0;
// head表示队头下标,tail表示队尾下标
private int head = 0;
private int tail = 0;
// 申请一个大小为capacity的数组
public ArrayQueue(int capacity) {
items = new String[capacity];
n = capacity;
}
// 入队
public boolean enqueue(String item) {
// 如果tail == n 表示队列已经满了
if (tail == n) return false;
items[tail] = item;
++tail;
return true;
}
// 出队
public String dequeue() {
// 如果head == tail 表示队列为空
if (head == tail) return null;
// 为了让其他语言的同学看的更加明确,把--操作放到单独一行来写了
String ret = items[head];
++head;
return ret;
}
}
数据搬移
随着不停的进入队列,出队的操作,队列尾部会没有多余的空间,但之前出队的数据会空出空间。这就需要将剩余的数据搬到空闲的空间中。
但可以不用在每次出队时搬移数据。如果没有空闲空间,只需要在 入队时,集中出发一次数据搬移操作就行。
// 入队操作,将item放入队尾
public boolean enqueue(String item) {
// tail == n表示队列末尾没有空间了
if (tail == n) {
// tail ==n && head==0,表示整个队列都占满了
if (head == 0) return false;
// 数据搬移
for (int i = head; i < tail; ++i) {
items[i-head] = items[i];
}
// 搬移完之后重新更新head和tail
tail -= head;
head = 0;
}
items[tail] = item;
++tail;
return true;
}
链表队列实现
循环队列
首尾相连,是一个环
确定好队空和队满的判定条件
队满的条件是tail == n,对空的条件是head==tail
公式:head=(tail+1)%n
public class CircularQueue {
// 数组:items,数组大小:n
private String[] items;
private int n = 0;
// head表示队头下标,tail表示队尾下标
private int head = 0;
private int tail = 0;
// 申请一个大小为capacity的数组
public CircularQueue(int capacity) {
items = new String[capacity];
n = capacity;
}
// 入队
public boolean enqueue(String item) {
// 队列满了
if ((tail + 1) % n == head) return false;
items[tail] = item;
tail = (tail + 1) % n;
return true;
}
// 出队
public String dequeue() {
// 如果head == tail 表示队列为空
if (head == tail) return null;
String ret = items[head];
head = (head + 1) % n;
return ret;
}
}
阻塞队列和并发队列
阻塞队列其实就是在队列基础上增加了阻塞操作。当没有数据时阻塞操作,当队列满了时阻塞操作。
生产者 - 消费者模型
可以通过协调“生产者”和“消费者”的个数,来提高数据的处理效率。
多个线程同时操作队列,会存在线程安全问题。
线程安全的队列我们叫作并发队列。
对于大部分资源有限的场景,当没有空闲资源时,基本上都可以通过“队列”这种数据结构来实现请求排队。
思考
1、除了线程池这种池结构会用到队列排队强求,你还知道哪些类似的池结构或者场景
消息队列