目录
由于顺序队列每次在出队时,都要牵扯到数组头部的删除,还要进行元素搬移O(N),故引入循环队列。
1.定义
- front:指向循环队列的第一个元素索引。(出队)
- tail:指向循环队列的最后一个元素的下一个位置。(入队)arr[tail] = x。尾部插入元素时更方便。
规定在循环队列中浪费一个空间,这个空间不能存储元素。(判断满和空的区别)
例:现在要存储的元素个数为k,数组大小要开辟k + 1。
2.如何判断当前循环队列为空/为满?
- 为空:front == tail;
- 为满:tail + 1 == front; 实际为 (tail + 1) % data.length == front;(size = data.length - 1;)
每次front和tail添加元素或删除元素后向后移动:
- (front + 1) % data.length
- (tail + 1) % data.length
取模的核心:当走到数组末尾时,继续从头开始入队和出队。
3.方法实现
public class LoopQueue implements Queue{
private int[] data;
//存储元素个数,仅用front和tail来计算有效元素个数
private int size;
//指向队首元素下标
private int front;
//指向队尾元素的下一个位置下标
private int tail;
public LoopQueue(int k) {
data = new int[k + 1];
}
//具体方法实现
//...
}
3.1.入队
/**
* 入队
* @param value
*/
@Override
public void offer(int value) {
//判断队列是否已满
if(isFull()) {
System.err.println("Queue is full!");
return;
}
data[tail] = value;
tail = (tail + 1) % data.length;
size++;
}
3.2.出队
/**
* 出队
* @return
*/
@Override
public int poll() {
//判断队列是否为空
if(isEmpty()) {
System.err.println("Queue is empty!");
return -1;
}
int value = data[front];
front = (front + 1) % data.length;
size--;
return value;
}
3.3.查队首元素
/**
* 查队首
* @return
*/
@Override
public int peek() {
if(isEmpty()) {
System.err.println("Queue is empty!");
return -1;
}
return data[front];
}
3.4.查队尾元素
/**
* 查队尾元素
* @return
*/
public int getTail() {
if(isEmpty()) {
System.out.println("Queue is empty!");
return -1;
}
//最后一个元素的下标
int index = tail == 0 ? data.length - 1 : tail - 1;
return data[index];
}
3.5.判断队列是否已满
/**
* 判断队列是否已满
* @return
*/
public boolean isFull() {
if((tail + 1) % data.length == front) {
return true;
}
return false;
}
3.6.判断队列是否为空
/**
* 判断队列是否为空
* @return
*/
public boolean isEmpty() {
return tail == front;
}
3.7.获得队列有效元素个数
/**
* 获得队列有效元素个数
* @return
*/
public int getSize() {
return size;
}
3.8.toString()方法
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("front[");
//取得最后一个元素的索引
int lastIndex = tail == 0 ? data.length - 1 : tail - 1;
//遍历循环队列
for (int i = front; i != tail;) {
sb.append(data[i]);
if(i != lastIndex) {
sb.append(",");
}
i = (i + 1) % data.length;
}
sb.append("]tail");
return sb.toString();
}
4.总代码实现
public class LoopQueue implements Queue{
private int[] data;
//存储元素个数,仅用front和tail来计算有效元素个数
private int size;
//指向队首元素下标
private int front;
//指向队尾元素的下一个位置下标
private int tail;
public LoopQueue(int k) {
data = new int[k + 1];
}
/**
* 入队
* @param value
*/
@Override
public void offer(int value) {
//判断队列是否已满
if(isFull()) {
System.err.println("Queue is full!");
return;
}
data[tail] = value;
tail = (tail + 1) % data.length;
size++;
}
/**
* 出队
* @return
*/
@Override
public int poll() {
//判断队列是否为空
if(isEmpty()) {
System.err.println("Queue is empty!");
return -1;
}
int value = data[front];
front = (front + 1) % data.length;
size--;
return value;
}
/**
* 查队首
* @return
*/
@Override
public int peek() {
if(isEmpty()) {
System.err.println("Queue is empty!");
return -1;
}
return data[front];
}
/**
* 查队尾元素
* @return
*/
public int getTail() {
if(isEmpty()) {
System.out.println("Queue is empty!");
return -1;
}
//最后一个元素的下标
int index = tail == 0 ? data.length - 1 : tail - 1;
return data[index];
}
/**
* 判断队列是否已满
* @return
*/
public boolean isFull() {
if((tail + 1) % data.length == front) {
return true;
}
return false;
}
/**
* 判断队列是否为空
* @return
*/
public boolean isEmpty() {
return tail == front;
}
/**
* 获得队列有效元素个数
* @return
*/
public int getSize() {
return size;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("front[");
//取得最后一个元素的索引
int lastIndex = tail == 0 ? data.length - 1 : tail - 1;
//遍历循环队列
for (int i = front; i != tail;) {
sb.append(data[i]);
if(i != lastIndex) {
sb.append(",");
}
i = (i + 1) % data.length;
}
sb.append("]tail");
return sb.toString();
}
}
5.测试实现
public class QueueTest {
public static void main(String[] args) {
LoopQueue loopQueue = new LoopQueue(3);
loopQueue.offer(1);
loopQueue.offer(3);
loopQueue.offer(5);
System.out.println(loopQueue); //front[1,3,5]tail
loopQueue.poll();
System.out.println(loopQueue); //front[3,5]tail
System.out.println(loopQueue.getTail()); //5
System.out.println(loopQueue.peek()); //3
}
}