1.队列是一个有序列表,可以用数组或者链表表示。
2.遵循先入先出的原则:先存入队列的数据,要先取出。后存入的要后取出。
数组模拟队列
- 队列本身是一个有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下。其中maxSize是该队列的最大容量。
- 因为队列的输出、输入分别从前后端来处理,因此需要两个变量front及rear分别记录前后端的下标。
- 初始化
- rear初始值默认为-1;
- rear指向队列尾的位置(就是队列尾)
- front初始值默认为-1;
- front指向队列首的前一个位置(不是队列首)
- 将数据存入队列(addQueue):
- 将尾部指针往后移,rear+1,如果front=rear,则队列为空
- 若rear小于最大下标maxSize-1,那么将数据存入rear所指的数组元素中。否则无法存入。 rear==maxSize-1,则队列已满。
- 当数据出队列时:
- 首指针往后移:front+1
代码实现:
public class DemoQueue {
/*
当将数据存入队列时:
1.将尾指针往后移:rear+1,当front==rear,队列为空
2.若尾指针rear==maxSize-1时,队列满,无法存入数据
当数据出队列时:
首指针往后移:front+1
*/
private int maxSize;//数组最大容量
private int rear;//尾指针
private int front;//首指针
private int[] arr;//实现队列的数组
public DemoQueue(int arrMaxsize) {//含参构造方法,传入参数为最大容量
maxSize = arrMaxsize;//获取最大容量
arr = new int[maxSize];//根据最大容量,创建一个数组
//初始化指针
front = -1;//front指向队列首的前一个位置(不是队列首)
rear = -1;//rear指向队列尾的位置(就是队列尾)
}
//2,判断 队列是否为满,若尾指针rear==maxSize-1时,队列满,无法存入数据
public boolean isfull() {
/* if (rear==maxSize-1){
return true;
}else {
return false;
}*/
return rear == maxSize - 1;
}
//1.判断队列是否为空,当front==rear,队列为空
public boolean isnull() {
return rear == front;
}
//1.添加数据到队列,将尾指针往后移:rear+1
public void addData(int i) {
if (isfull()) {
System.out.println("队列已满");
} else {
arr[++rear] = i;
}
}
//数据出队列
public int getData() {
if (isnull()) {//如果队列为空,抛出一个异常
throw new RuntimeException("队列为空");
} else {
return arr[++front];
}
}
//显示队列所有数据
public void showArr() {
if (isnull()) {
System.out.println("队列为空");
} else {
for (int i : arr) {
System.out.println(i);
}
}
}
//显示队列第一个数据
public void showFirst(){
if (isnull()){
System.out.println("队列为空");
}else{
System.out.println(arr[front+1]);
}
}
}
主程序验证:
import java.util.Scanner;
public class ArrayQueue {
public static void main(String[] args) {
//创建一个队列,最大容量为3
DemoQueue demoQueue = new DemoQueue(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':
demoQueue.showArr();
break;
case 'a':
System.out.println("请输入一个数");
demoQueue.addData(scanner.nextInt());
break;
case 'g':
try {
System.out.println("取出数据为:" + demoQueue.getData());
} catch (RuntimeException i) {
System.out.println(i.getMessage());
}
break;
case 'h':
demoQueue.showFirst();
break;
case 'e':
scanner.close();
loop=false;
break;
}
}
}
}
结果:
"G:\IntelliJ IDEA 2019.2.3\jbr\bin\java.exe" "-javaagent:G:\IntelliJ IDEA 2019.2.3\lib\idea_rt.jar=33297:G:\IntelliJ IDEA 2019.2.3\bin" -Dfile.encoding=UTF-8 -classpath G:\Java\IdeaProjects\dataStruts\out\production\days0302 ArrayQueue
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
s
队列为空
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
a
请输入一个数
12
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
a
请输入一个数
6
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
h
12
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
g
取出数据为:12
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
h
6
s(show),显示队列
e(exit),退出
a(add),添加数据
g(get),取出数据
h(head),查看头数据
e
Process finished with exit code 0
数组只能使用 而且数组还是有数据的 没有达到复用的效果
解决方案:将这个数组使用算法,改进成一个环形的队列 取模 %
优化:使用数组模拟环形队列的思路分析
- 初始化
- front 变量的含义做一个调整: front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素
- front 的初始值 = 0
- rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定.
- rear 的初始值 = 0
- 添加和取出数据
- 当队列满时,条件是(rear + 1) % maxSize == front 【满】
- 对队列为空的条件, rear == front
- 队列中有效的数据的个数 (rear + maxSize - front) % maxSize
队列满条件是(rear + 1) % maxSize == front 解释:
1.为什么取模:
%运算是一个神奇的运算,它是一个哈希运算
因为取模%操作可以把任意数压缩到一定区间内,比如,你想知道一年中第 122 天是星期几,那么你就用【121%7】,结果为二。诸如此类。就拿这个例子里的maxsize = 8 来说, 一定会有(任意数 % 8)的结果小于8。
尾指针rear在一直不断增加,到最后比maxsize还大,所以取模以后可以将rear固定在0到maxsize的范围内
2.为什么rear+1
实际上,(rear + 1) % maxSize == front时候,数组中还要一个空余,但是如果不浪费这个空间的话,此条件将会和队列为空的条件一致,会导致无法区分队列是满还是空
队列中有效的数据的个数 (rear + maxSize - front) % maxSize解释:
(rear -front+ maxSize)% maxSize:相当于|rear-front|
class CircleArrayQueue {
//数组的最大容量
private int maxSize;
//队列头部
//front 变量的含义做一个调整: front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素
private int front;
//队列尾部
//rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定.
private int rear;
//模拟队列的数组
private int[] arr;
//创建队列的构造器
public CircleArrayQueue(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
//队列头 前一个位置
front = 0;
//队列尾 就是尾部(包含)
rear = 0;
}
//判断队列是不是满了
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
//判断队列是否为空
public boolean isEmpty() {
return front == rear;
}
//添加数据到队列
public void addQueue(int n) {
//判断队列是不是已经满了
if (this.isFull()) {
System.out.println("队列已经满了,不能再加入");
} else {
//直接放到数据
arr[rear] = n;
//把 rear 后移 这里必须考虑取模
rear = (rear + 1) % maxSize;
}
}
//获取数据
public int getQueue() {
//判断队列是否为空
if (this.isEmpty()) {
throw new RuntimeException("队列为空,不能取出数据");
} else {
//这里需要分析front是指向队列的第一个元素
//1.先把front对应的值保留到一个临时变量
//2.front后移考虑取模
//将保存的数据返回
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
}
//显示数据所有的数据
public void showQueue() {
//遍历
if (this.isEmpty()) {
System.out.println("队列为空");
} else {
//思路 从 front进行遍历 遍历多少个元素
//元素有效个数为(rear-front+maxsize)%maxsize
for (int i = front; i <front+(rear-front+Maxsize)%Maxsize; i++) {
System.out.println("arr["+i%Maxsize+"]"+":"+arr[i%Maxsize]);
//front可能会超界,i=front,所以i%maxsize防止超界
}
}
}
//显示队列头数据
public void showQueueFront() {
if (this.isEmpty()) {
System.out.println("队列为空");
} else {
System.out.println(arr[front]);
}
}
}
import java.io.IOException;
import java.util.Scanner;
public class DemoQueue {
public static void main(String[] args) {
ArrayQueue arrayQueue = new ArrayQueue(3);
Scanner scanner = new Scanner(System.in);
boolean loop = true;
char key = ' ';
while (loop) {
System.out.println("e(exit),退出");
System.out.println("s(show),显示队列内数据");
System.out.println("f(first),显示队列第首数据");
System.out.println("a(add),添加数据");
System.out.println("g(get),取出数据");
key = scanner.next().charAt(0);
switch (key) {
case 'e':
scanner.close();
loop = false;
break;
case 's':
try {
arrayQueue.showArray();
} catch (RuntimeException e) {
System.out.println(e.getMessage());
} finally {
break;
}
case 'f':
try {
arrayQueue.showFirst();
} catch (RuntimeException e) {
System.out.println(e.getMessage());
} finally {
break;
}
case 'a':
try {
arrayQueue.addData(scanner.nextInt());
} catch (RuntimeException e) {
System.out.println(e.getMessage());
} finally {
break;
}
case 'g':
try {
arrayQueue.getData();
} catch (RuntimeException e) {
System.out.println(e.getMessage());
} finally {
break;
}
}
}
}
}
来源:CSDN
作者:Mango学习日记
链接:https://blog.csdn.net/wangzilong1995/article/details/104576064