应用场景
排队,先到先得。
基本介绍
队列是一个有序列表,可以用数组或是链表实现
遵循先入先出的原则,即先存入队列的数要先取出后存入队列的数要后取出。
数组模拟队列
队列本身是有序列表,因为队列的输出、输入是分别从前后端来处理,因此需要两个变量front
及rear
分别记录队列前后端的下标,front
会随着数据输出而改变,而rear
则是随着数据输入而改变,maxSize
是该队列的最大容量。
思路
入队操作
- 将尾指针向后移:
rear + 1
,当front == rear
时队列为空。 - 如果尾指针
rear
小于队列的最大下标maxSize - 1
,则将数据存入rear
所指的数组元素中;如果rear == maxSize - 1
,则表示队列满,无法存入。
代码实现
package com.zls.demo03;
import java.util.Scanner;
public class ArrayQueueDemo {
public static void main(String[] args) {
ArrayQueue arrayQueue = new ArrayQueue(3);
char key = ' '; //接收用户输入
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while (loop){
System.out.print("s(show):显示队列; ");
System.out.print("e(exit):退出程序; ");
System.out.print("a(add):添加数据到队列; ");
System.out.print("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 value = scanner.nextInt();
arrayQueue.addQueue(value);
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;
}
}
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 rear == front;
}
//添加数据到队列
public void addQueue(int num){
if (isFull()){
System.out.println("队列已经存满,不能再添加数据");
return ;
}
arr[++ rear] = num;
}
//获取队列头数据,并让数据出队列
public int getQueue(){
if (isEmpty()){
throw new RuntimeException("队列为空,不能取数据");
}
return arr[++ front];
}
//获取队列头数据,但不取出
public int headQueue(){
if (isEmpty()){
throw new RuntimeException("队列为空,不能读数据");
}
return arr[front + 1];
}
//显示队列所有数据
public void showQueue(){
if (isEmpty()){
System.out.println("队列为空");
return ;
}
for (int i = front + 1; i <= rear; i++) {
System.out.printf("arr[%d] = %d\t",i,arr[i]);
}
System.out.println();
}
}
优化实现
刚刚的实现方式,数组只使用一次就不能再用了,会造成很大的空间浪费。
思路
将数组看成是一个环形的,可以通过取模的方式实现。
front
指向队列的第一个元素;rear
指向队列的最后一个元素的后一个位置。- 当队列满时的条件为:
(rear + 1) % maxSize = front
。 - 当队列为空的条件为:
rear == front
。 front
初始值为0
;rear
的初始值为1
。- 队列中有效的数据个数为:
(rear + maxSize - front) % maxSize
。
代码实现
package com.zls.demo03;
import java.util.Scanner;
public class CircleArrayQueueDemo {
public static void main(String[] args) {
CircleArray queue = new CircleArray(4);
char key = ' '; //接收用户输入
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while (loop){
System.out.print("s(show):显示队列; ");
System.out.print("e(exit):退出程序; ");
System.out.print("a(add):添加数据到队列; ");
System.out.print("g(get):从队列中取出数据; ");
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;
}
}
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 num){
if (isFull()){
System.out.println("队列已经存满,不能再添加数据");
return ;
}
arr[rear ++] = num;
rear %= maxSize;
}
//获取队列头数据,并让数据出队列
public int getQueue(){
if (isEmpty()){
throw new RuntimeException("队列为空,不能取数据");
}
int value = arr[front ++];
front %= maxSize;
return value;
}
//获取队列头数据,但不取出
public int headQueue(){
if (isEmpty()){
throw new RuntimeException("队列为空,不能读数据");
}
return arr[front];
}
//显示队列所有数据
public void showQueue(){
if (isEmpty()){
System.out.println("队列为空");
return ;
}
for (int i = front; i < front + size(); i++) {
System.out.printf("arr[%d] = %d\t",i % maxSize,arr[i % maxSize]);
}
System.out.println();
}
public int size(){
return (rear + maxSize - front) % maxSize;
}
}
Java实例
package com.zls.demo03;
import java.util.LinkedList;
import java.util.Queue;
public class TestDemo {
public static void main(String[] args) {
//add()和remove()方法在失败的时候会抛出异常(不推荐)
Queue<String> queue = new LinkedList<String>();
//添加元素
queue.offer("a");
queue.offer("b");
queue.offer("c");
queue.offer("d");
queue.offer("e");
for(String q : queue){
System.out.println(q);
}
System.out.println("===");
System.out.println("poll="+queue.poll()); //返回第一个元素,并在队列中删除
for(String q : queue){
System.out.println(q);
}
System.out.println("===");
System.out.println("element="+queue.element()); //返回第一个元素
for(String q : queue){
System.out.println(q);
}
System.out.println("===");
System.out.println("peek="+queue.peek()); //返回第一个元素
for(String q : queue){
System.out.println(q);
}
}
}