队列
队列介绍:
1、队列是一个有序列表,可以用数组或是链表来实现。
2、遵循先进先出的原则。即:先存入队列的数据,要先取出。后存入的数据,后取出
数组模拟队列示意图:
- maxSize 是该队列的最大容量
- 存入数据时从 尾节点存入,尾节点移动,头节点不动
- 取出数据时从头节点取出,头节点移动,尾节点不动
加入数据的思路分析
当我们将数据存入队列时称为 ”addQueue“,addQueue 的处理需要有两个步骤
1、将尾指针往后移:rear+1,当front == rear 【队列为空】
2、若尾指针 rear 小于队列的最大下标 maxSize-1,则将数据存入所指的数组元素中,否则无法存入数据。 rear == maxsize -1 [队列满]
tip:数组模拟队列是从 0 开始, 第 一 个数据是放在第 0 的位置,第 二个数据是放在第 1 的位置,因此 队列最大值是 Maxsize - 1
代码实现:
package com.aiguigu.queue;
import java.util.Scanner;
public class ArrayQueueDemo {
public static void main(String[] args) {
ArrayQueue queue = 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(getQueue):从队列取出数据");
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("程序退出");
}
}
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;//指向队列头部,front是指向队列头的前一个位置
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;
}
//添加数据到队列
arr[++rear] = n;//让 rear 后移,在 rear 的位置插入数据
}
//获取队列的数据
public int getQueue(){
//判断队列是否为空
if (isEmpty()){
System.out.println("队列为空的,没有数据~~");
throw new RuntimeException("队列空,不能取数据");//抛异常的效果和 return一样
}
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()){
System.out.println("队列为空的,没有数据~~");
throw new RuntimeException("队列空,不能取数据");//抛异常的效果和 return一样
}
return arr[front + 1];
}
}
运行效果:
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
队列为空的,没有数据~~
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
2
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
arr[0]=2
arr[1]=0
arr[2]=0
arr[3]=0
arr[4]=0
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
3
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
4
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
arr[0]=2
arr[1]=3
arr[2]=4
arr[3]=0
arr[4]=0
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
5
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
6
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
arr[0]=2
arr[1]=3
arr[2]=4
arr[3]=5
arr[4]=6
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
1
队列已满,不能加入数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
h
队列的头数据是2
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是2
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
h
队列的头数据是3
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是3
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是4
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是5
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是6
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
队列为空的,没有数据~~
队列空,不能取数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
1
队列已满,不能加入数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
e
程序退出
Process finished with exit code 0
数组模拟队列存在的问题和优化
1、目前数组使用一次1就不能用,没有达到服用的效果
2、将这个数组使用算法,改进成一个环形的队列 取模:%
数组模拟环形队列
思路:
1、front 变量的含义做一个调整:front 就指向队列的第一个元素,就是说 arr[front] 是队列的第一个元素, front的初始值 = 0
2、rear 变量的含义做一个调整:rear 就指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定, rear的初始值 = 0
3、当队列满时,条件是 (rear + 1 + maxSize)% maxSize = front
4、队列为空的条件,rear == front
5、队列有效的数据的个数 (rear+maxSize-front)% maxSize
6、我们就可以在原来的队列上修改得到,一个环形队列
个人理解:
当 rear 的上面那个位置是front 时 队列满 因此是 (rear+1 + maxsize)%maxsize = front
Rear – front 表示 它两节点中间还有几个元素,但是 rear 有可能跑到 front 前面 ,这样Rear – front 得到的值就是负数,但是元素个数不能是负数,因此加上maxsize 再对 maxsize 取模,这样既不影响 元素的真实个数 又能使 元素的真实个数一直为正数,
(Rear-front + maxsize)%maxsize
package com.aiguigu.queue;
import java.util.Scanner;
public class CircleAraayQueueDemo {
public static void main(String[] args) {
CircleArrayQueue circleQueue = new CircleArrayQueue(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(getQueue):从队列取出数据");
System.out.println("h(head):显示队列头的数据");
key = scanner.next().charAt(0);//接收一个字符
switch (key){
case 's'://显示数据
circleQueue.showQueue();
break;
case 'a'://添加数据
System.out.println("输入一个数");
int value = scanner.nextInt();
circleQueue.addQueue(value);
break;
case 'g'://取出数据
try {
int res = circleQueue.getQueue();
System.out.printf("取出的数据是%d\n",res);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h'://查看队列头的数据
try {
int res = circleQueue.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 CircleArrayQueue{
private int maxSize;//表示数组的最大容量
private int front;//队列头
private int rear;//队列尾
private int[] arr;//该数组用于存放数据,模拟队列
//创建队列的构造器
public CircleArrayQueue(int arrMaxSize){
maxSize = arrMaxSize ;
arr = new int[maxSize];
}
//判断队列是否已满
public boolean isFull(){
return (rear+1+maxSize)%maxSize== front ;
}
//判断队列是否为空
public boolean isEmpty(){
return front == rear;
}
//添加数据到队列
public void addQueue(int n){
//判断队列是否已满
if(isFull()){
System.out.println("队列已满,不能加入数据");
return;
}
//添加数据到队列
arr[rear] = n;//直接将数据加入
rear = (rear+1)%maxSize;//将 rear后移,这里考虑到取模
}
//获取队列的数据
public int getQueue(){
//判断队列是否为空
if (isEmpty()){
System.out.println("队列为空的,没有数据~~");
throw new RuntimeException("队列空,不能取数据");//抛异常的效果和 return一样
}
int value = arr[front];//先定义一个变量将数组的值存放再移动front
front = (front+1)%maxSize;//front后移,考虑取模
return value;
}
//显示队列信息
public void showQueue(){
//判断队列是否为空
if (isEmpty()){
System.out.println("队列为空的,没有数据~~");
return;
}
//从 front开始遍历,变历 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-front+maxSize) % maxSize;
}
//显示队列的头数据,注意不是取数据
public int headQueue(){
//判断队列是否为空
if (isEmpty()){
System.out.println("队列为空的,没有数据~~");
throw new RuntimeException("队列空,不能取数据");//抛异常的效果和 return一样
}
return arr[front];
}
}
运行结果:
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
队列为空的,没有数据~~
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
10
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
20
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
30
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
40
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
arr[0]=10
arr[1]=20
arr[2]=30
arr[3]=40
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
50
队列已满,不能加入数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
h
队列的头数据是10
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是10
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
arr[1]=20
arr[2]=30
arr[3]=40
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据