数组模拟队列(具体代码实现)
注意: 上面的数组模拟队列指的是模拟费环形队列
具体代码:
package com.ffyc.queue;
public class ArrayQueue {
//表示数组的最大容量,在这里也表示队列的最大容量
private int maxSize;
//队列头(指向了队列中第一个元素的前一个位置)
private int front;
//队列尾(指向了队列中最后一个元素的位置)
private int rear;
//该数组用于存放数据,模拟队列
private int[] arr; // 这里我们创建了一个整形数据队列
//创建队列的构造器
public ArrayQueue(int arrMaxsize){
/*
这里我们就是做了四个成员变量的初始化
*/
maxSize = arrMaxsize;
front = -1; //显示初始化为-1
rear = -1; //显示初始化为-1
arr = new int[arrMaxsize];
}
//判断队列是否已满(在向队列中添加数据的时候就要判断队列是否已满)
public boolean isFull(){
//如果rear等于maxSize-1,也即是返回一个true的时候就表示队列已满
return rear == maxSize-1;
}
//判断队列是否为空
public boolean isEmpty(){
/*
为什么rear 等于 front就可以判断队列为空?
其实很简单,我们的rear指向了队尾的元素,而front指向了队首元素的上一个位置,
也就是front指向的位置是没有元素的,而当rear == front的时候,我们知道rear是
指向了队尾元素的,那么这个时候这个位置即指向了队尾的元素又是不存在的,那么也就
表示队尾元素是不存在的,而队尾元素不存在其实就是表中没有元素 --> 因为当表中有
元素的话,即使表中只有仅仅一个元素,那么这一个元素也是既做了队首,又做了队尾
*/
return rear == front;
}
//往队列中添加数据
public void addQueue(int n){
//判断队列是否已满
if(isFull()){
System.out.println("队列已满,不能加入数据~");
return;
}
/*
后面这两步其实可以等价的替代为: arr[++rear] = n;
*/
rear++; //rear后移
arr[rear] = n;
}
//获取队列中的数据,出队列
public int getQueue(){
//判断队列是否为空
if(isEmpty()){
//通过手动的抛出一个异常对象来告诉用户队列为空
throw new RuntimeException("队列为空,不能删除数据~");
/*
注意: 在我们手动抛出异常对象(throw)的代码之后就不能写其他的可执行代码了,因为一旦执行到了手动抛出异常
对象的这条代码这里,这个时候这里立马会抛出一个异常对象,那么这时候后面的代码都不会执行,这个时候异常会一直向上抛出
直到将异常对象抛给虚拟机,或者异常对象被使用异常处理机制解决为止
*/
}
front++; //front后移
return arr[front];
}
//显示队列中所有的数据
public void showQueue(){
//遍历
if(isEmpty()){
System.out.println("队列为空,没有数据~~");
return;
}
for(int i = 0 ; i < arr.length ; i++){
//这里我们使用了printf()方法进行了格式化输出
System.out.printf("arr[%d]=%d\n",i,arr[i]);
}
}
//显示队列的头数据,注意: 这里只是显示队列的头数据,而不是删除头数据
public int headQueue(){
//判断队列是否为空
if(isEmpty()){
throw new RuntimeException("队列为空,没有数据~~");
}
//因为这个时候front表示的是队列中首个元素的上一个位置,这个时候我们要输出首个元素(也就是头元素),
//那么这个时候就要先后移(+1)再输出
return arr[front+1];
}
}
- 对于这种方式下我们对队列中的数据进行删除和添加时都是先进行自加再操作
这里我们对上面的程序进行测试:
package com.ffyc.queue;
import java.util.Scanner;
public class ArrayQueueTest {
public static void main(String[] args) {
System.out.println("测试数组模拟队列的案例~~");
//创建一个队列(非环形队列)
ArrayQueue queue = new ArrayQueue(3);
//创建一个字符变量接收用户输入
char key = ' ';
Scanner scanner = new Scanner(System.in);
//循环退出的条件
boolean loop = true;
//输出一个菜单
while(loop){
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 res = queue.getQueue();
System.out.printf("取出的数据是%d\n",res);
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try{
int res = queue.headQueue();
System.out.printf("队列头的数据是%d\n",res);
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
//退出程序
case 'e':
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出~~");
}
}
上面的程序中在模拟队列的时候没有使用实现环形队列,因此模拟实现队列的数组使用一次之后就不能再使用了 --> 也就是没有达到复用的效果
- 为什么上面的举例中数据使用一次就不能使用了?因为我们没有将队列设置为环形队列,那么上面的代码的数组中的元素装到最大位置之后这个数组中就再也无法添加元素了,即使我们删除了元素之后也不行,也会显示添加失败,因为我们在删除数组中数据的时候没有进行取模处理(没有进行%判断)
- 那么我们要如何解决这个只能添加一次元素的问题?
- 我们要将这个队列设置为一个环形队列
- 那么我们要如何解决这个只能添加一次元素的问题?