1.简介
队列为一个有序列表,可以用数组或链表来实现。
先进先出原则。先存入队列的数据先取出,后存进队列的数据后取出。
这里对比一下,栈是后来者居上
下面使用数组来模拟队列,用数组的结构来存储队列的数据:
Queue中两个指针,front为队首,rear为队尾。maxSize是该队列的最大容量。当有数据加进来时,加到队尾,front没有变化,而rear在增加。当数据被取出,从对头取出,rear没有变化,而front在增加。front随数据输出而改变,rear随数据输入而改变。
怎么记呢?就是,现在你在军训排队,然后你来晚了迟到了,你这时候偷偷排到队尾去,队尾就后移了。然后教官是站在队伍前方的,他对着队伍说:出列!然后队头这个人就站出来了,队头这个位置就空出来了。
还可以就按超市排队结账,肯定是排在前面的人先结账,后面来的就在队尾排队,你排到了队尾,队就变长了,队尾就后移了。前面的队头的人结完账走了,队伍就变短了,队头也后移到了下一个人。
2.将数据加入队列思路:
数据加入队列,addQueue。入队处理有两个步骤:
- 将尾指针后移,rear+1。若队满了则不能加入数据。
- 若尾指针rear小于队列最大下标maxSize-1,则将数据存入rear指的这个数组元素中。否则就无法存入数据。
注:因为数组下标从0开始,队列容量maxSize,所以最大下标是maxSize-1。
3.从队列取出数据思路:
若数组为将头指针后移,front+1。若队为空则不能取出数据。
4.判断队列满和空:
当front==rear则队列为空
当rear==maxSize-1则队列满
5.将数据加入队列代码:
package com.xjj.queue;
import java.nio.Buffer;
import java.util.Scanner;
public class ArrayQueue {
public static void main(String[] args) {
//创建一个队列
MyArrayQueue arrayQueue = new MyArrayQueue(3);
//测试从控制台输入数据到队列
char key = ' ';//接收用户输入
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.print("s(show)展示队列\t");
System.out.print("e(exit)退出\t");
System.out.print("a(add)添加数据\t");
System.out.print("g(get)取出数据\t");
System.out.print("h(head)查看队头数据\t\n");
key = scanner.next().charAt(0);//接收一个字符
switch (key) {
case 's':
arrayQueue.showQueue();
break;
case 'a':
System.out.println("添加一个数据");
try{
int value = scanner.nextInt();//假如需要输入一个整数
arrayQueue.addQueue(value);
}
catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'g':
try {//这里用try catch是因为可能有异常抛出
int res = arrayQueue.getQueue();
System.out.printf("取出的数据为:%d\n", res);
} catch (Exception e) {
System.out.println(e.getMessage());//这里的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 MyArrayQueue {
private int maxSize;//队列的最大容量
private int front;//队列头
private int rear;//队列尾
private int[] QueueArr;//用于存放数据的数组,模拟队列
//先创建队列的构造器
public MyArrayQueue(int arrMaxSize) {
maxSize = arrMaxSize;
QueueArr = 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()) {
//抛出异常
throw new RuntimeException("队满,无法加数据");
}
rear++;//rear后移一位就是加进去了
QueueArr[rear] = n;//这个队尾位置就放这个数据
}
//从队列中取数据,出队列
public int getQueue() {
if (isEmpty()) {
//抛出异常
throw new RuntimeException("队空,无法取数据");
}
front++;//front后移一位就是队头,因为front本来是指向队头前一个位置,后移一位就正好指向队头了
return QueueArr[front];//返回队头这个数据
}
//显示队列所有数据
public void showQueue() {
if (isEmpty()) {
System.out.println("队列为空,没有数据");
return;
}
//遍历
for (int i = 0; i < QueueArr.length; i++) {
System.out.printf("QueueArr[%d]=%d\n", i, QueueArr[i]);
}
}
//显示队列的队头数据
public int headQueue() {
//判断是否为空
if (isEmpty()) {
throw new RuntimeException("队列为空,没有数据");
}
//从队列头前一位指向队列头
return QueueArr[front+1];
}
}
6.运行结果:
设置队列最大长度为3。先显示队列数据,再把5加入队列,显示队列
再把6和7加入队列,显示队列
在队满的情况下把8加入队列,显示队满无法加数据
再查看队头数据,为5,再从队列取数据,取出后显示队列,再查看队头数据,为6,再从队列取数据,再查看队头数据,为7
再从队列取出数据,查看队头数据,发现队列为空,再从队列取数据、显示队列,都是为空。最后退出程序。
可以看到确实用数组实现了队列。
不过这样直接用数组,取出数据之后原来队首的位置也不能放数据,浪费了。
我们从运行结果也可以看到,从队列中取出数据后,只是指针移动了,用来模拟的数组中队头数据还是在那里。但是随着指针移动,也指不到队头的前面了。
也就是数组使用一次就不能用了,没有达到复用的效果。要改进的话我们可以把这个数组改造成一个环型队列,用取模的方式。
下一篇写环形队列^_^加油加油