队列是具有一定操作约束的线性表,对比堆栈的插入删除只在一端进行,队列是在一端插入(入队),在另一端删除(出队),也就是我们经常说的先进先出。
可以通过一个数组、一个记录队头的变量front以及一个记录队尾的变量rear来实现队列的顺序存储结构。假定现在申请来个长度为6的队列空间,分别派遣了job1…job6,一段时间后,由于先进先出,job1出队,形成下图的状态:
这时候派遣下一个job会发现,数组后面没有足够的空间可以分配,造成数组空间的浪费。为了解决这个问题,我们可以在分配完数组5这个位置后,让它调回0这个位置,也就是形成一个闭环,如图:
我们是根据front和rear的距离状态来判断这个队列是空的还是满的,距离状态分别有0、1、2、3、4、5六种情况,但是实际这个闭环存在7种情况,圆环内没有job,或者有1-6个job,要使用6种状态来表达七种情况显然是不可能的,如果现在添加job7,front=rear,我们不能以此判断它是表达队列是空的还是满了。为避免这种情况的发生,我们可以牺牲一个空间来表达满,也就是我们往队列中添加5个job的时候,我们就认为队列满了。
具体代码实现如下:
public class MyQueue {
private int front; //队头,指向队头前一个位置
private int rear; //队尾,指向队尾位置
private Object[] arr; //储存位置
public Object[] getArr() {
return arr;
}
public void setArr(Object[] arr) {
this.arr = arr;
}
public MyQueue() {
}
//初始化,length 需要开辟数组的长度
public MyQueue(int length) {
this.arr = new Object[length];
}
//判断队列是否满
public boolean isFull() {
int maxSize = arr.length;
return ((rear + 1) % maxSize == front);
//从1开始添加队列,如果数组长度是6,添加5个队列便为满状态,(5+1)%6=0=front
}
//判断队列是否空
public boolean isEmpty() {
int maxSize = arr.length;
return (rear == front);
}
//入队
public void AddQ(Object data) {
if (isFull()) {
System.out.println("该队列已经满了");
} else {
rear = (rear + 1) % arr.length;
arr[rear] = data;
System.out.println("入队元素为" + data);
}
}
//出队
public void DeleteQ() {
if (isEmpty()) {
System.out.println("这是一个空队列");
} else {
front = (front + 1) % arr.length;
Object data = arr[front];
arr[front] = null;
System.out.println("出队元素为" + data);
}
}
}
public static void main(String[] args) {
MyQueue myQueue = new MyQueue(6);
myQueue.AddQ("第1个");
myQueue.AddQ("第2个");
myQueue.AddQ("第3个");
myQueue.AddQ("第4个");
myQueue.AddQ("第5个");
myQueue.AddQ("第6个");
myQueue.DeleteQ();
myQueue.AddQ("第6个");
for (int i = 0; i < myQueue.getArr().length; i++) {
System.out.println(myQueue.getArr()[i]);
}
}
/*
输出结果为:
入队元素为第1个
入队元素为第2个
入队元素为第3个
入队元素为第4个
入队元素为第5个
该队列已经满了
出队元素为第1个
入队元素为第6个
第6个
null
第2个
第3个
第4个
第5个
*/