一、定义
什么是队列?队列(queue)又叫先进先出表,它是一种运算受限的线性表。其限制是只允许在表的一端进行插入数据和另一端取数据。插入数据的一端是队尾,取数据的一端是队头。
队列的数据结构:数组或者链表实现
队列的常用场景:生产者生产数据放入队列缓存,消费者去消费数据。
二、循环队列
普通的队列往其中添加元素,队头指针和队尾指针分别指向队头和队尾,当队列中元素出队之后,队头指针和队尾指针指在了队尾,此时再有元素进来时会发生假溢出的情况。为此循环队列进行弥补。循环队列是指队头和队尾相连的队列,接下来我们用图来说明入队和出队整个过程。

假设循环队列总容量为N,并且预留一个空的位置作为队列空,满,长度判断标志:
队列空:front==rear;
队列满:(rear+1)%N==front;
队列元素个数:(rear – front + N)%N
三、队列的算法实现
通过上面的分析,队列的操作:队列大小,入队(队尾),出队(队头)

public class Queue<E> {
Node<E> front; //始终指向
Node<E> head; //队头
Node<E> tail; //队尾
int QUEUE_SIZE; //模拟队列初始化大小
static final int DEFAULT_QUEUE_SIZE = 5; //设置默认队列大小
public Queue(){
this(DEFAULT_QUEUE_SIZE);
}
public Queue(int queueSize){
QUEUE_SIZE = queueSize + 1; //因为要空出一个节点,所以这里加1
checkQueueSize();
}
/**
* 入队,从队尾添加元素
*/
public boolean push(E e){
if (head == tail) {
Node<E> node = new Node(e,0, null); //入队,第一个节点
front = head = node; //更新队头
Node<E> rear = new Node(null, head.index + 1, null); //队尾
node.next = rear; //下一个节点是空队尾
tail = rear; //更新队尾指针
isClose();
} else {
full(); //判断是否队满
if (tail.next != null) { //已经形成闭环
tail.e = e;
tail = tail.next;
} else { //还未形成闭环
Node<E> rear = new Node(null, tail.index + 1, null); //队尾
tail.e = e; //队尾添加元素
tail.next = rear; //添加新的空队尾
tail = rear; //更新队尾指针
isClose();
}
}
return true;
}
void isClose(){
if(size() == QUEUE_SIZE - 1) //相等则说明可以形成闭环,因为要留一个空节点,所以这里减1
tail.next = front;
}
/**
* 出队,从队头取出元素
*/
public E pop(){
if(empty())
return null;
E e = head.e;
head.e = null; //节点数据清空
head = head.next; //更新队头位置
return e;
}
/**
* 获取队列中元素个数
* (tail – head + QUEUE_SIZE)%QUEUE_SIZE
*/
public int size(){
return (tail.index - head.index + QUEUE_SIZE) % QUEUE_SIZE;
}
/**
* 队列是否为空
*/
public boolean empty(){
return head == tail;
}
/**
* 判断队列是否已满
* (rear+1)%N==front
*/
void full(){
if((tail.index + 1) % QUEUE_SIZE == head.index)
throw new IndexOutOfBoundsException("队列已满,入队失败");
}
/**
* 初始化的队列大小检查
*/
void checkQueueSize(){
if(QUEUE_SIZE < 1)
throw new IndexOutOfBoundsException("QUEUE_SIZE : " + QUEUE_SIZE);
}
/**
* 节点的定义
* @param <E>
*/
private static class Node<E>{
E e; //元素
int index; //当前节点的下标,从0开始直到QUEUE_SIZE
Node<E> next; //下一个节点
Node(E e, int index, Node<E> next){
this.e = e;
this.index = index;
this.next = next;
}
}
}

写到这里,队列通过单链表已经实现了。队列还可以通过数组来实现。
队列是一种运算受限的线性表,允许在表的一端插入数据,另一端取出数据,遵循先进先出原则。循环队列解决了普通队列可能出现的假溢出问题,通过队头和队尾的循环连接实现。文章介绍了如何使用链表实现队列,包括入队、出队操作,并提供了Java代码示例。
4512

被折叠的 条评论
为什么被折叠?



