概述
- 队列是一个有序列表,可以用数组和链表来实现
- 队列遵循**先进先出**的原则,根据入队的先后顺序依次出队
数组方式实现队列
构成
- maxSize:队列的最大容量
- front:队列头部
- rear:队列尾部
- front指向第一个元素的前一个位置
- rear指向最后一个元素的后一个位置
代码实现
class ArrayQueue {
/**
* 队列的最大容量
*/
private int maxSize;
/**
* 队列头,指向第一个数据的前一个位置
*/
private int front;
/**
* 队列尾,指向最后一个数据
*/
private int rear;
/**
* 队列值
*/
private int[] array;
/**
* 构造一个新的队列
*
* @param maxSize
* 队列大小
*/
public ArrayQueue(int maxSize) {
this.maxSize = maxSize;
this.front = -1;
this.rear = -1;
this.array = new int[maxSize];
}
/**
* 判满
*
* @return 队列是否已满
*/
public boolean isFull() {
return rear == maxSize - 1;
}
/**
* 判空
*
* @return 队列是否为空
*/
public boolean isEmpty() {
return front == rear;
}
/**
* 入队
*
* @param value
* 入队的值
*/
public void add(int value) {
// 判断队列是否已满
if (isFull()) {
System.out.println("队列已满");
return;
}
// 队尾向后移一位,将值加入
rear++;
array[rear] = value;
}
/**
* 出队
*
* @return 出队的值
*/
public int get() {
// 判断队列是否为空
if (isEmpty()) {
throw new RuntimeException("队列为空");
}
front++;
return array[front];
}
/**
* 展示队列的全部数据
*/
public void showAll() {
if (isEmpty()) {
System.out.println("队列为空");
return;
}
//从队列头遍历到队列尾
for (int i = front+1; i <= rear; i++) {
System.out.printf("array[%d]=%d\n", i, array[i]);
}
}
/**
* 展示队列的头数据
*/
public void showHead() {
if (isEmpty()) {
throw new RuntimeException("队列为空");
}
System.out.println(array[front + 1]);
}
}
如上使用数组实现的队列存在一个问题,即队列只能进行一次存储,当array存满后队列不能再进行存储
优化实现——数组模拟环形队列
- front指向队列的第一个元素
- rear指向队列的最后一个元素的后一个位置,这个位置将被空出来,用于作为判空和判满的区分
代码实现
class ArrayRingQueue {
/**
* 队列的最大容量,由于存在
*/
private int maxSize;
/**
* 队列头,指向队列的第一个数据
*/
private int front;
/**
* 队列尾,指向最后一个数据的后一个位置
*/
private int rear;
/**
* 队列值
*/
private int[] array;
/**
* 构造一个新的队列
*
* @param maxSize
* 队列大小
*/
public ArrayRingQueue(int maxSize) {
this.maxSize = maxSize;
this.front = 0;
this.rear = 0;
this.array = new int[maxSize];
}
/**
* 判满
*
* @return 队列是否已满
*/
public boolean isFull() {
//rear指向的是最后一个元素的后一个位置(不放值的约定位置),队满时在front的前一个位置
//如果rear已经指向了数组尾部,则队满时对应的front在数组头部,所以需要通过取模运算来取到数组头部
return (rear+1)%maxSize==front;
}
/**
* 判空
*
* @return 队列是否为空
*/
public boolean isEmpty() {
return front == rear;
}
/**
* 入队
*
* @param value
* 入队的值
*/
public void add(int value) {
// 判断队列是否已满
if (isFull()) {
System.out.println("队列已满");
return;
}
//因为rear指向的是队尾的后一位,所以将新元素直接赋值
array[rear] = value;
// 队尾向后移一位
//如果rear已经在数组尾部,则需要通过取模取到数组头部
rear = (rear+1)%maxSize;
}
/**
* 出队
*
* @return 出队的值
*/
public int get() {
// 判断队列是否为空
if (isEmpty()) {
throw new RuntimeException("队列为空");
}
//此时front指向的时队头的元素,所以直接返回
int res = array[front];
//队头向后移一位
//如果front已经在数组尾部,则需要通过取模取到数组头部
front = (front+1)%maxSize;
return res;
}
/**
* 展示队列的全部数据
*/
public void showAll() {
if (isEmpty()) {
System.out.println("队列为空");
return;
}
//从队列头开始,遍历有效数据个数的次数
for (int i = front; i <front+size(); i++) {
System.out.printf("array[%d]=%d\n", i%maxSize, array[i%maxSize]);
}
}
/**
* 获取队列中有效数据的个数
* @return 有效数据的个数
*/
public int size() {
//当队尾已经回到数组头部,队头在数组尾部,则有效数据为数组长度减去队头加上队尾的位置
//如果队尾还在数组尾部,队头在数组头部,就多加了一个maxSize,所以通过取模来抵消这个多余的maxSize,因为有效数据个数不会超过maxSize,所以不会影响上一种情况
return (rear+maxSize-front)%maxSize;
}
/**
* 展示队列的头数据
*/
public void showHead() {
if (isEmpty()) {
throw new RuntimeException("队列为空");
}
System.out.println(array[front]);
}
}