Ø队列
队列介绍
-
概念:队列是一个有序列表,可以用数组或是链表来实现
-
原则:先入先出;即:先存入队列的数据,要先取出,后存入的要后取出
-
示意图:(使用数组模拟队列示意图)
1.数组模拟队列
1)队列数组声明:
-
maxSize表示队列的最大容量
-
front记录队列前端的下标,rear记录队列后端的下标;front会随着数据输出而改变,而rear是随着数据输入而改变
-
向队列添加数据时:
- 将尾指针后移:rear+1,当front=rear ==>队列为空
- 若rear<maxSize-1,则存入数据;否则无法存入。当rear==maxSize-1==>队列已满
2)代码实现:
package com.queue;
/*
@author qw
@date 2020/7/17 - 21:03
**/
import java.util.Scanner;
public class ArrayQueueDemo {
public static void main(String[] args) {
//创建队列
ArrayQueue arrayQueue = new ArrayQueue(3);
char ch = ' ';//接收用户输入
Scanner sc = 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):查看队列头的数据");
ch=sc.next().charAt(0);//接收一个字符
switch (ch){
case 's'://显示队列
arrayQueue.showQueue();
break;
case 'a'://向队列添加数据
System.out.println("请输入需要添加的数据:");
int value=sc.nextInt();
arrayQueue.addQueue(value);
break;
case 'g'://从队列取出数据
try {
int result= arrayQueue.getQueue();
System.out.println("取出的数据是"+result);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h'://查看队列头的数据
try {
int result=arrayQueue.headQueue();
System.out.println("取出队列头数据是"+result);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e'://退出
sc.close();
loop=false;
break;
default:
break;
}
}
System.out.println("程序退出。");
}
}
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 front==rear;
}
//向队列添加数据,入队
public void addQueue(int n){
//判断队列是否已满
if(isFull()){
System.out.println("队列已满,不能添加数据。");
return;
}
rear++;//尾指针后移
arr[rear]=n;
}
//从队列获取数据,出队
public int getQueue(){
//判断队列是否为空
if(isEmpty()){
throw new RuntimeException("队列为空,不能取数据。");
}
front++;//头指针后移
return arr[front];
}
//遍历队列
public void showQueue(){
if(isEmpty()){
System.out.println("队列为空,没有数据。");
return;
}
for(int i=0;i<arr.length;i++){
System.out.println("arr["+i+"]="+arr[i]);
}
}
//显示队列头数据
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("队列为空,没有数据。");
}
return arr[front+1];
}
}
3)问题分析并优化:
- 目前数组使用一次就不能再用,没有达到复用的效果
- 将这个数组使用算法,该进成一个环形的队列 取模:%
2.数组模拟环形队列
1)分析:
- 尾索引的下一个为头索引时表示队列已满,即将队列容量空出一个作为约定,这个在做判断队列满时注意 (rear+1)%maxSize===front —> 满
- rear==front —> 空
2)思路:
- front指向队列的第一个元素,即arr[front]为队列的第一个元素。front的初始值=0
- rear指向队列的最后一个元素的后一个位置,为了空出一个位置作为约定。rear的初始值=0
- 当队列满时,(rear+1)%maxSize==front
- 当队列为空时,rear==front
- 队列中有效数据的个数为:(rear + maxSize - front) % maxSize
- 以上,即可在原来的队列基础上,修改得到一个环形队列。
3)代码实现:
package com.queue;
/*
@author qw
@date 2020/7/20 - 22:05
**/
import java.util.Scanner;
public class CircleArrayQueueDemo {
public static void main(String[] args) {
//创建队列
CircleArray circleArray = new CircleArray(4);//队列数据最多3个
char ch = ' ';//接收用户输入
Scanner sc = 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):查看队列头的数据");
ch=sc.next().charAt(0);//接收一个字符
switch (ch){
case 's'://显示队列
circleArray.showQueue();
break;
case 'a'://向队列添加数据
System.out.println("请输入需要添加的数据:");
int value=sc.nextInt();
circleArray.addQueue(value);
break;
case 'g'://从队列取出数据
try {
int result= circleArray.getQueue();
System.out.println("取出的数据是"+result);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h'://查看队列头的数据
try {
int result=circleArray.headQueue();
System.out.println("取出队列头数据是"+result);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e'://退出
sc.close();
loop=false;
break;
default:
break;
}
}
System.out.println("程序退出。");
}
}
class CircleArray{
private int maxSize;//数组最大容量
//front指向队列的第一个元素,即arr[front]为队列的第一个元素。
// front的初始值=0
private int front;//队列头
//rear指向队列的最后一个元素的**后一个位置**,为了空出一个位置作为约定。
//rear的初始值=0
private int rear;//队列尾
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+1)%maxSize;//尾指针后移,环形队列需要取模
}
//从队列获取数据,出队
public int getQueue(){
//判断队列是否为空
if(isEmpty()){
throw new RuntimeException("队列为空,不能取数据。");
}
//将front对应的值保存在一个临时变量temp中
int temp=arr[front];
//将front后移,考虑取模
front=(front+1)%maxSize;
//返回临时变量
return temp;
}
//遍历队列
public void showQueue(){
if(isEmpty()){
System.out.println("队列为空,没有数据。");
return;
}
//从front开始遍历,遍历有效个数
for(int i=front;i<front+size();i++){
System.out.println("arr["+(i%maxSize)+"]="+arr[i%maxSize]);
}
}
//求出当前队列有效数据的个数
public int size(){
return (rear+maxSize-front)%maxSize;
}
//显示队列头数据
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("队列为空,没有数据。");
}
return arr[front];
}
}