基本队列
队列是一个有序列表,遵循先进先出的原则。从队首出,从队尾进。
在代码中定义:
maxSize—队列的最大容量。front,队首,随着数据的输出而改变。rear,队尾,随着数据的输入而改变
注意,在这里约定front和rear的初始值为-1.
- 1.front变量的含义 front=-1 指向队列头部的前一个位置
- 2.rear变量的含义 :rear=-1 指向队列尾,指向队列尾的数据(即就是队列的最后一个数据)
- 3.当队列满的条件是:rear==maxSizes-1
- 4.当队列尾空的条件是 rear==front
- 5在入队或者出队的时候,都是指针先移动,再取数据。
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 val=scanner.nextInt();
arrayQueue.addQueue(val);
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 res=arrayQueue.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("程序退出");
}
}
//使用数组模拟队列----ArrayQueue类
class ArrayQueue{
private int maxSizes;//表示数组的最大容量
private int front;//队列头
private int rear;//队列尾
private int[] arr;//该数组用于存放数据
public ArrayQueue(int arrMaxSize){
maxSizes=arrMaxSize;
arr=new int[maxSizes];
front=-1;//指向队列头部的前一个位置
rear=-1;//指向队列尾,指向队列尾的数据(即就是队列的最后一个数据)
//队列尾部进,队列头部出
}
//判断队列是否满
public boolean isFull(){
return rear==maxSizes-1;
}
//判断队列是否空
public boolean isEmpty(){
//当队首==队尾,队列为空
return rear==front;
}
//添加数据到队列
public void addQueue(int n){
//判断队列是否满
if (isFull()){
System.out.println("队列满,不能加入数据");
return;
}else {
rear++;
arr[rear]=n;
//arr[++rear]=n;
}
}
//获取队列的数据,出队列
public int getQueue(){
//判断队列是否空
if (isEmpty()){
//通过抛出异常
throw new RuntimeException("队列空,不能取数据");
}else {
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];//将front加一的数据返回,实际上front的值并没有发生改变
}
}
环形队列
但是,这样的代码存在一个问题:数组只能使用一次,没有复用性可言。
为了解决这个问题,模拟环形队列。
- 数组模拟环形队列思路:
- 1.front变量的含义做一个调整:front指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素 front的初始值=0
- 2.rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间为约定. rear的初始值=0
- 3.当队列满的条件是:(rear+1)%maxSize==front
- 4.当队列尾空的条件是 rear==front
- 5.有效数据的个数 (rear+maxSize-front)%maxSize
注意:判断队列为空、队列满以及队列有效个数的条件,这里都要使用取模运算,否则会出现索引越界的情况
package com.atguigu.queue;
import java.util.Scanner;
public class CircleArrayQueueDemo {
public static void main(String[] args) {
System.out.println("测试数组模拟环形队列~~");
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 val=scanner.nextInt();
arrayQueue.addQueue(val);
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 res=arrayQueue.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("程序退出");
}
}
class CircleArray{
private int maxSize;//表示数组的最大容量
private int front;//队列头
private int rear;//队列尾
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;
}else {
arr[rear]=n;
//将rear后移,这里必须考虑取模
rear=(rear+1)%maxSize;
}
}
//获取队列的数据,出队列
public int getQueue(){
//判断队列是否空
if (isEmpty()){
//通过抛出异常
throw new RuntimeException("队列空,不能取数据");
}else {
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];//将front加一的数据返回,实际上front的值并没有发生改变
}
}