数组实现环形队列
实现:解决之前单向的问题,让数组达到复用的效果,即:当我们从数组队列中取出了数据,那取出数据后后这个空间可以再次使用
思路分析
首先对rear 和 front的含义做调整
- rear:指向队列最后一个元素的后一个位置 初始值为0
- front:指向队列的头一个元素 初始值为0
当 rear
指针指向maxSize - 1
时,也就是rear = maxSize - 1时,需要判断rear
的前面是否有空闲空间,也就说front
是否产生了变化并且已经不在初始的那个位置了
说明:
1.rear指向的位置始终都是没有数据的,目的是预留一个位置作为约定
2.rear和front含义发生调整后,判断队列满的条件是( rear + 1 )% maxsize = front
举例:如上图 rear = 7,front = 0,maxSize =8时 (7+1)%8=0 此时队列满
解释:可以看出当rear跟front相邻时就是队列满的条件,如:
rear | front | 状态 |
---|---|---|
0 | 1 | 满 |
1 | 2 | 满 |
2 | 3 | 满 |
以此类推可以看出当rear + 1 = front
时就可以说队列满,那为什么要%maxsize呢?
rear | front | 状态 |
---|---|---|
7 | 0 | 满 |
可以看到rear到达maxsize - 1 时rear + 1= front
就不满足了,所以需要取模从而达到数组空间复用的效果
3.判断队列为空的条件是rear = front
4.队列中有效数据的个数是(rear + maxsize - front) % maxsize
为什么要取模?答:因为是环形队列,rear有可能指到队列最前面。
打个比方,当rear = 0,maxsize = 4 ,front = 0
时,该队列中有多少个有效的数据?
分析:(0 + 3 - 0)% 3 = 0,该队列中有效的数据个数为0个,因为rear = front ,则证明是空队列
代码实现
import java.util.Scanner;
public class CircleArrayQueueDemo {
public static void main(String[] args) {
//测试
//创建一个环形队列
CircleArray queue = new CircleArray(4); //其队列的有效数据最大是3
char key = ' ';//接收用户输入
Scanner scanner = new Scanner(System.in);
//输出一个菜单
boolean loop = true;
while (loop){
System.out.println();
System.out.println("s(show):显示队列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加数据到队列");
System.out.println("g(get):从队列取出数据");
System.out.println("h(head):查看数据头数据");
key = scanner.next().charAt(0);
switch (key){
case 's':
queue.showQueue();
break;
case 'a':
System.out.println("输出一个数字");
int value = scanner.nextInt();
queue.addQueue(value);
break;
case 'g':
try {
int result = queue.getQueue();
System.out.println("取出的数据:"+result);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int result = queue.headQueue();
System.out.println("队列头的数据是:"+result);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close();
loop = false;
break;
}
}
System.out.println("程序退出!");
}
}
class CircleArray{
private int maxSize;//表示数组的最大容量
private int front;//队列头,初始值0 指向队列的第一个元素
private int rear;//队列尾,初始值0 指向最后一个元素的后一个位置
private int[] arr;//该数组用于存放数据,模拟队列
public CircleArray(int arrMaxSize){
maxSize = arrMaxSize;
//初始化数组
arr = new int[maxSize];
front = 0;
rear = 0;
}
/**
* 判断是否满
*/
public boolean isFull(){
return (rear + 1)% maxSize == front;
}
/**
* 判断是否为空
*/
public boolean isEmpty(){
return rear == front;
}
/**
* 添加数据到队列
*/
public void addQueue(int n){
if(isFull()){
System.out.println("队列已满!");
return;
}
arr[rear] = n ;
//将rear后移,这里必须考虑取模
rear = (rear + 1)% maxSize;
}
/**
* 获取队列的数据,出队列
*/
public int getQueue(){
if(isEmpty()){
throw new RuntimeException("队列空,不能取数据");
}
//front指向队列的第一个元素
//1.先把front对应的值保留到一个临时变量
//2.将front后移 考虑取模
//3.将临时保存的变量返回
int value = arr[front];
front = (front+1)%maxSize;
return value;
}
/**
* 显示队列数据
*/
public void showQueue(){
if(isEmpty()){
System.out.println("队列空");
return;
}
//从front开始遍历
for(int i = front ;i<front+getSize();i++){
System.out.println(arr[i%maxSize]);
}
}
/**
* 当前队列有效数据的个数
*/
public int getSize(){
return (rear + maxSize - front)% maxSize;
}
/**
* 显示队列的头数据 注意不是取数据
*/
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("队列空,没有数据");
}
return arr[front];
}
}
总结
- 环形队列判满条件:
(rear +1) % maxsize == front
- 环形队列判空条件:
rear == front
- 环形队列有效数据的个数
(rear + maxsize - front) % maxsize
- 环形队列中rear的含义:指向队列中最后一个数据的前一个位置,因为要预留一个空间作为约定
- 环形队列中front的含义:指向队列头(即:队列中的第一个数据)