数组模拟环形队列
对队列进行入队操作时,队头指针不变,队尾指针后移一位,对队列进行出队操作时,队头指针后移一位,队尾指针不变,通过这样的操作过后,很有可能某些数据域空闲,导致空间浪费,此时循环队列能很好的解决这一问题,当队尾指针到达数组的最后一个位置,且数组还有空闲的数据域时,队尾指针可以再次到达数组的起始位置,从而使得数组可以重复使用。
一、使用数组模拟环形队列思路分析
1、front变量的含义:
front指针指向队列的第一个元素,即arr[front]就是队列中的第一个元素,其初始值为0;
2、rear变量的含义 :
rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定。rear的初始值为0
3、判断条件:
队列满时:(rear+1)%maxsize = front
队列空时: rear = front
举个例子来说明一下:
现在我们有一个长度为5的数组,通过它来模拟环形队列,当我们不对队列进行任何操作,队列为空时,rear、front的初始值都为0,此时front=rear;当我们入队操作,添加数据,1、2、3、4号位都已装有数据时,即为队列满,不是说是用长度为5的数组模拟的环形队列吗,怎么装到4号位就满了呢,因为我们留了一个数据域作为约定;此时front指向0号位,rear指向4号位,此时通过计算发现,当rear+1在对数组长度5取模运算可得出结果位0,刚好等于front的值。
入队操作之后我们在玩一玩出队操作,我们取出一个数据,对头指针front向后移动一位,即front+1,此时front为1;取出一个数据过后,我们又想再往队列中添加数据,怎么办呢?我们知道,往队列中添加数据是通过队尾指针来实现的,向队列中添加一个数据后,队尾指针rear+1,指向5号位,rear=5;此时队列又变满了,通过 rear+1再对数组长度取模发现,其结果刚好为1,与front的值相等;所以可以得出结论:
队列满时:(rear+1)%maxsize = front
队列空时: rear = front
4、队列中数据的有效个数
通过以上的分析,队列中的有效数据个数应满足: (rear+maxsize-front)%maxsize
二、代码
public class CircleArrayQueenTest {
public static void main(String[] args) {
//test
System.out.println("测试数组模拟环形队列的案例~~~~");
CircleArrayQueen arrayQueen = new CircleArrayQueen(4);//说明设置4,其队列的有效数据最大是3
char key = ' ';
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.println("s(show):显示所有数据");
System.out.println("a(add):添加数据到队列");
System.out.println("e(exit):退出程序");
System.out.println("g(get):从队列得到数据");
System.out.println("h(head):查看队列头部数据");
key = scanner.next().charAt(0);//结束接受一个字符
switch (key) {
case 's':
arrayQueen.showQueue();
break;
case 'a':
System.out.print("输入一个整型数据:");
int data = scanner.nextInt();
arrayQueen.addQueen(data);
break;
case 'g':
try {
int getData = arrayQueen.getQueen();
System.out.printf("取出的数据为:%d\n", getData);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int headData = arrayQueen.headQueue();
System.out.printf("队头数据:%d\n", headData);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出");
}
}
class CircleArrayQueen {
private int maxSize;
private int front;//队头指针,指向对头数据的前一个
private int rear;//队尾指针,指向队尾的数据
private int[] arr;//数组模拟队列
public CircleArrayQueen(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
}
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
public boolean isEmpty() {
return rear == front;
}
public void addQueen(int data) {
if (isFull()) {
System.out.println("数据满,不能再加数据!");
return;
}
arr[rear] = data;
rear = (rear + 1) % maxSize;
}
//得到数据
public int getQueen() {
if (isEmpty()) {
throw new RuntimeException("队列为空");
}
//这里需要分析出front是指向队列的第一个元素
//1.先将front对应的值保留到一个临时变量
//2.将front后移,考虑取模
//3.将临时保存的 变量返回
int data = arr[front];
front = (front + 1) % maxSize;
return data;
}
public void showQueue() {
if (isEmpty()) {
System.out.println("队列空,没有数据~~~~");
return;
}
for (int i = front; i < front + Size(); i++) {
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
}
}
//求出当前队列的有效数据个数
public int Size() {
return (rear + maxSize - front) % maxSize;
}
public int headQueue() {
if (isEmpty()) {
throw new RuntimeException("队列为空,没有数据~~~");
}
return arr[front];
}
}