队列
一、使用场景:银行排队系统
二、概念
a.队列是一个有序列表,可以用数组或者链表来实现。
b.遵循先入先出的原则
c.数组队列示意图,maxSize最大容量、Queuce类、front队列前端,rear队列后端,front随数据输出而变化,rear随数据输入而变化
d.当我们将数据存入队列时,称为,“addQueue”它需要处理两个步骤
①将尾指针往后移,rear+1 ,当front==rear时队列为空
②若尾指针rear小于队列的最大下标maxSize-1,则将数据存入rear所指的数组元素中,否则无法存入数据,rear==maxSize-1时队列满,无法存入数据。
三、代码实现
import java.util.Scanner;
public class QueueDemo {
public static void main(String[] args) {
//测试
ArrayQueue arrayQueue = 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':
arrayQueue.showQueue();
break;
case 'a':
System.out.println("请输入一个值");
int i = scanner.nextInt();
arrayQueue.addQueue(i);
break;
case 'g':
try {
int res = arrayQueue.getQueue();
System.out.printf("取出的数据%d\n",res);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int headQueue = arrayQueue.headQueue();
System.out.printf("队列头数据%d\n",headQueue);
break;
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e'://退出
scanner.close();
loop=false;
break;
default:
break;
}
}
System.out.printf("程序退出啦啦啦");
}
}
//数组模拟队列
class ArrayQueue {
private int maxSize;//数组最大容量
private int front ;//队列头,分析出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++;
arr[rear]=n;
}
//数据出队列
public int getQueue(){
if (isEmpty()) {
//通过抛出异常来处理
throw new RuntimeException("队列为空不能取数据");
}
front++;//front后移
return arr[front];
}
//显示队列的所有数据
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];
}
}
四、上述代码的缺陷及改造成环形队列
①、目前数组使用一次就不能用,没有达到复用的效果
②、将这个数组使用算法,改进一个环形的队列
1)、front变量含义做一个调整:指向队列第一个元素,arr[front]就是队列的第一个元素,front初始值为0
2)、rear变量含义做一个调整:指向队列的最后一个元素的后一个位置,因为我们希望空出一个空间作为约定,rear的初始值为0。
3)、当队列满时,条件是,(rear+1)%maxSize=front【满】
4)、当队列为空时,条件是rear=front
5)、队列中有效的数据个数(rear+maxSize-front)%maxSize
6)、我们就可以在原来的队列上修改得到一个环形队列
③、环形队列代码实现
import java.util.Scanner;
public class CircleArrayQueueDemo {
public static void main(String[] args) {
//测试
CircleArray arrayQueue = new CircleArray(4);//设置为4,有效数据最大是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':
arrayQueue.showQueue();
break;
case 'a':
System.out.println("请输入一个值");
int i = scanner.nextInt();
arrayQueue.addQueue(i);
break;
case 'g':
try {
int res = arrayQueue.getQueue();
System.out.printf("取出的数据%d\n",res);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int headQueue = arrayQueue.headQueue();
System.out.printf("队列头数据%d\n",headQueue);
break;
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e'://退出
scanner.close();
loop=false;
break;
default:
break;
}
}
System.out.printf("程序退出啦啦啦");
}
}
class CircleArray{
private int maxSize;//数组最大容量
private int front ;//队列头,指向队列第一个元素,arr[front]就是队列的第一个元素,front初始值为0
private int rear;//队列尾,指向队列的最后一个元素的后一个位置,因为我们希望空出一个空间作为约定,rear的初始值为0。
private int[] arr; //该数组用于存放数据,模拟队列
public CircleArray(int arrMaxSize){
maxSize=arrMaxSize;
arr=new int[maxSize];
}
//判断队列是否满
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是指向队列的第一个元素,首相,把front对应的值保存到一个临时的变量,将front后移,考虑取模,将临时保存的变量返回
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+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];
}
}