队列的数组表示。(下面图一图二代码段一均来自尚硅谷)
示意图如上。
front队列第一个元素之前一个位置,rear指向队列尾端,maxSize表示队列最大容量
存在问题:数组只能使用一次,即数组存满,在取空后,无法继续存储新的队列。
解决方式:1)(尚硅谷)教程解决方案,将数组模拟成环形队列 ,使用取模实现。此解决方案思路如图:
package com.algorithm.queue01;
import org.junit.Test;
import java.util.Scanner;
public class ArrayQueueDemo02 {
public static void main(String[] args) {
//创建一个队列对象
ArrayCircleQueue arrayQueue = new ArrayCircleQueue(5);
char key ;//接收用户输入
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while(loop){
System.out.println("s(show):显示队列v2");
System.out.println("e(exit):退出队列v2");
System.out.println("a(add):添加数据到队列v2");
System.out.println("g(get):从队列取出数据v2");
System.out.println("h(head):查看队列头部数据v2");
key = scanner.next().charAt(0);//接收一个字符
switch(key){
case 's':
arrayQueue.showQueue();
break;
case 'e':
scanner.close();//关闭输入
loop = false;//关闭目录
System.out.println("程序已退出");
break;
case 'a':
System.out.println("请输入一个数据:");
int n;
n = scanner.nextInt();//接收一个数据
arrayQueue.addQueue(n);
break;
case 'g':
try {
int res = arrayQueue.getQueue();
System.out.printf("取出的数据是%d\n",res);
} catch (Exception e) {
//e.printStackTrace();
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int res = arrayQueue.headQueue();
System.out.printf("队列头的数据是%d\n",res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
default:
break;
}
}
}
}
//使用数组模拟队列
class ArrayCircleQueue {
private int maxSize;//表示队列最大容量
private int front;
private int rear;
private int[] arr;//该数组用于存放数据
//创建队列的构造器
public ArrayCircleQueue(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+1)%maxSize;//此时rear指向最后一个元素的后一个位置,在数组后面满了但前面还有
//空余时,取模,将新的元素放到数组前面。
}
//获取队列数据,数据出队列
public int getQueue(){
//判断是否为空
if(isEmpty()){
//通过抛出异常来处理
throw new RuntimeException("队列为空,不能取数据!");
}
int a=arr[front];//此时的front指向队列的第一个元素,取出数据即取出此时arr[front]的值,取出之后将front后移
arr[front]=0;//将取出值的位置变成0,便于观察
front = (front + 1) % maxSize;
return a;
}
//显示队列所有数据
public void showQueue(){
if(isEmpty()){
System.out.println("队列为空,无数据!");
return;
}
//从front开始遍历,遍历(rear+maxSize-front)%maxSize个元素;
for(int i=0;i<(rear+maxSize-front)%maxSize;i++){
System.out.printf("arr[%d]=%d\n",i,arr[(front+i)%maxSize]);
}
}
//显示队列头部数据是多少,不是取数据
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("队列空,无数据");
}
return arr[front+1];
}
}
2)自我思考后给出的解决方案:固定front 存取只变动rear,取头一个数据之后,整体数据向前移位。适用于队列长度不长的时候,因为有数组元素前移的操作(使用循环实现)。
这种情况下:front依然指向数组头部元素的前一个位置,rear指向队尾元素。
package com.algorithm.queue;
import java.util.Scanner;
public class ArrayQueueDemo {
public static void main(String[] args) {
//创建一个队列对象
ArrayQueue arrayQueue = new ArrayQueue(5);
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':
arrayQueue.showQueue();
break;
case 'e':
scanner.close();//关闭输入
loop = false;//关闭目录
System.out.println("程序已退出");
break;
case 'a':
System.out.println("请输入一个数据:");
int n;
n = scanner.nextInt();//接收一个数据
arrayQueue.addQueue(n);
break;
case 'g':
try {
int res = arrayQueue.getQueue();
System.out.printf("取出的数据是%d\n",res);
} catch (Exception e) {
//e.printStackTrace();
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int res = arrayQueue.headQueue();
System.out.printf("队列头的数据是%d\n",res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
default:
break;
}
}
}
}
//使用数组模拟队列
class ArrayQueue {
private int maxSize;//表示队列最大容量
private int front;
private int rear;
private int[] arr;//该数组用于存放数据
//创建队列的构造器
public ArrayQueue(int arrMaxSize) {
maxSize = arrMaxSize;
arr = new int[maxSize];
front = -1;//指向队列头部,指向队列头的前一个位置
rear = -1;//指向队列尾部,指向队列尾部的数据(即就是队列最后一个数据)
}
//判断队列是否满
public boolean isFull() {
return rear == maxSize - 1;
}
//判断队列是否为空
public boolean isEmpty() {
return rear == front;
}
//添加数据到队列
public void addQueue(int n) {
if(isFull()){
System.out.println("队列已满,无法加入数据");
return;
}
rear++;//让rear后移
arr[rear]=n;
}
//获取队列数据,数据出队列
public int getQueue(){
//判断是否为空
if(isEmpty()){
//通过抛出异常来处理
throw new RuntimeException("队列为空,不能取数据!");
}
rear--;
int a=arr[front+1];
// arr[front+1]=arr[front+2];
// arr[front+2]=arr[front+3];
for(int i=1;i< arr.length;i++){
arr[front+i]=arr[front+i+1];
}
arr[rear+1]=0;
return a;
}
//显示队列所有数据
public void showQueue(){
if(isEmpty()){
System.out.println("队列为空,无数据!");
return;
}
for(int i=0;i<arr.length;i++){
System.out.printf("arr[%d]=%d\n",i,arr[i]);
}
}
//显示队列头部数据是多少,不是取数据
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("队列空,无数据");
}
return arr[front+1];
}
}