队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,队列是一种操作受限制的线性表,队列又称为先进先出(FIFO—first in first out)线性表。
进行插入操作的端称为队尾,进行删除操作的端称为队头
常说的队列是指单向队列:
通过操作尾指针rear、头指针front、数组可以模拟单向队列
rear == maxSize
判断队列是否满rear == front
判断队列是否为空package com.company.queue;
import java.util.Scanner;
/**
* @author zfk
* 使用数组模拟队列
*/
public class ArrayQueueDemo {
/**
* @param args
* 测试
*/
public static void main(String[] args) {
ArrayQueue arrayQueue = new ArrayQueue(3);
char key = ' ';
boolean loop = true;
Scanner scanner = new Scanner(System.in);
System.out.println("s(show):显示队列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加数据到队列");
System.out.println("g(get):从队列取出数据");
System.out.println("h(showHead):显示队列头数据");
System.out.println("============================");
while (loop){
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.println("取出的数据是:" + res);
}
catch (Exception e){
System.out.println(e.getMessage());
}
break;
//显示队列头数据
case 'h':
try {
int head = arrayQueue.showHeadQueue();
System.out.println("取出的队列头数据是:" + head);
}
catch (Exception e){
System.out.println(e.getMessage());
}
break;
//退出程序
case 'e':
scanner.close();
loop = false;
break;
default:
break;
}
}
}
}
class ArrayQueue{
//表示数组最大容量
private int maxSize;
//队列头
private int front;
//队列尾
private int rear;
//数组存放数据,模拟队列
private int[] arr;
//创建队列构造器
public ArrayQueue(int arrMaxSize){
this.maxSize = arrMaxSize;
this.arr = new int[maxSize];
//指向队列头部,第一个数据
front = 0;
//指向队列尾,队列最后一个数据后一位
rear = 0;
}
//判断队列是否满
public boolean isFull(){
return rear == maxSize;
}
//判断队列是否为空
public boolean isEmpty(){
return rear == front;
}
//添加数据到队列
public void addQueue(int n){
//判断是否满
if (isFull()){
System.out.println("队列已满,不能加入数据");
return;
}
arr[rear] = n;
//队尾后移
rear++;
}
//获取队列数据,获得队列头数据
public int getQueue(){
//判断队列是否为空
if (isEmpty()){
throw new RuntimeException("队列空,不能取数据");
}
int value = arr[front];
//front后移
front++;
return value;
}
//显示队列的所有数据
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 showHeadQueue(){
//判断是否为空
if (isEmpty()){
throw new RuntimeException("队列为空,没有数据");
}
return arr[front];
}
}
前面单向队列缺点在与“假溢出”
解决办法,设置循环队列
循环队列,逻辑上将数组元素q[0]与q[MAX-1]连接(实际并没有这样的硬件)
队首指针指向队列第一个元素
队尾指针指向队列最后一个元素后一位
在循环队列中,当队列为空时,有front=rear,而当所有队列空间全占满时,也有front=rear,所以为了区别这两种情况
设置循环队列时,特意留一个空存储单元
即当队列满时,是这种情况:
循环队列是对单向队列进行了一定的改变
判断为空、满、改变rear、front指针的位置使用取模的方式:rear = (rear + 1) % maxSize
,当指针指向空存储单元,在进一位就回到0
例如:maxSize=4,当rear=3,判断空时,4 % 4 = 0,即到队列首位
package com.company.queue;
import java.util.Scanner;
/**
* @author zfk
* 循环队列
*/
public class CircleArrayQueueDemo {
/**
* @param args
* 测试
*/
public static void main(String[] args) {
CircleArrayQueue arrayQueue = new CircleArrayQueue(4);
char key = ' ';
boolean loop = true;
Scanner scanner = new Scanner(System.in);
System.out.println("s(show):显示队列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加数据到队列");
System.out.println("g(get):从队列取出数据");
System.out.println("h(showHead):显示队列头数据");
System.out.println("============================");
while (loop){
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.println("取出的数据是:" + res);
}
catch (Exception e){
System.out.println(e.getMessage());
}
break;
//显示队列头数据
case 'h':
try {
int head = arrayQueue.showHeadQueue();
System.out.println("取出的队列头数据是:" + head);
}
catch (Exception e){
System.out.println(e.getMessage());
}
break;
//退出程序
case 'e':
scanner.close();
loop = false;
break;
default:
break;
}
}
}
}
class CircleArrayQueue{
//表示数组最大容量
private int maxSize;
//队列头,指向队列第一个元素
private int front;
//队列尾,指向最后一个元素的后一个位置
private int rear;
//数组存放数据,模拟队列
private int[] arr;
//创建队列构造器
public CircleArrayQueue(int arrMaxSize){
this.maxSize = arrMaxSize;
this.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("队列空,不能取数据");
}
int value = arr[front];
//front后移,考虑取模
front = (front + 1) % maxSize;
return value;
}
//显示队列的所有数据
public void showQueue(){
//判断是否为空
if (isEmpty()){
System.out.println("队列空,没有数据");
return;
}
//从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 + maxSize - front) % maxSize;
}
//显示队列的头数据
public int showHeadQueue(){
//判断是否为空
if (isEmpty()){
throw new RuntimeException("队列为空,没有数据");
}
return arr[front];
}
}