介绍
1.队列是一个有序列表,可以用数组或是链表来实现。
2.遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出
3.示意图:(使用数组模拟队列示意图)
数组模拟队列思路
队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图,其中maxSiz是该队列的最大容量。
因为队列的输出、输入是分别从前后端来处理,因此需要两个变量front及rar分别记录队列前后端的下标,font会随着数据输出而改变,而rear则是随着数据输入而改变,如图所示:
数组模拟线性队列
当我们将数据存入队列时称为”addQueue”,addQueue的处理需要有两个步骤
l.将尾指针往后移
rear+1,当font=rear【空】
2.若尾指针rear小于队列的最大下标maxSize-1,则将数据存入rear所指的数组元素中,否则无法存入数据。
rear==maxSize-1【队列满】
import java.util.Scanner;
public class Queue {
public static void main(String[] args) {
/*创建一个队列*/
ArrayQueue arrQueue = new ArrayQueue(3);
/*接收用户输入*/
char key = ' ';
Scanner sc = new Scanner(System.in);
boolean loop = true;
/*输出一个菜单*/
while (loop) {
System.out.println("s(show)\t");
System.out.println("e(exit)\t");
System.out.println("a(add)\t");
System.out.println("g(get)\t");
System.out.println("h(head)\t");
key = sc.next().charAt(0);
switch (key) {
case 's':
arrQueue.showQueue();
break;
case 'a':
System.out.print("please input:>");
int value = sc.nextInt();
arrQueue.addQueue(value);
break;
case 'g':
try {
int res = arrQueue.getQueue();
System.out.printf("you get %d\n", res);
} catch (Exception e) {
System.out.printf(e.getMessage());
}
break;
case 'h':
try {
int res = arrQueue.headQueue();
System.out.printf("the head is %d\n", res);
} catch (Exception e) {
System.out.printf(e.getMessage());
}
break;
case 'e':
sc.close();
loop = false;
break;
default:
break;
}
System.out.println("程序结束");
}
}
}
/*使用数组模拟队列,编写一个ArrayQueue类*/
class ArrayQueue {
/**
* 最大容量
*/
private int maxSize;
/**
* 队头与队尾
*/
private int front;
private int rear;
/**
* 存放数据,模拟队列
*/
private int[] arr;
/**
* 创建队列的构造器
*/
public ArrayQueue(int arrMaxSize) {
maxSize = arrMaxSize;
arr = new int[arrMaxSize];
/*指向队列头部的前一个位置*/
front = -1;
/*指向队列尾部的数据(队列最后一个数据)*/
rear = -1;
}
/**
* 判断队列是否满
*/
public boolean isFull() {
return rear == maxSize - 1;
}
/**
* 判断队列是否空
*/
public boolean isEmpty() {
return rear == front;
}
/**
* 添加数据到队列
*/
public void addQueue(int n) {
/*判断是否满*/
if (isFull()) {
System.out.println("队列已满");
}
rear++;
arr[rear] = n;
}
/**
* 获取队列数据
*/
public int getQueue() {
/*判断是否为空*/
if (isEmpty()) {
/*抛出异常*/
throw new RuntimeException("队列空");
}
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()) {
/*抛出异常*/
throw new RuntimeException("队列空");
}
return arr[front + 1];
}
}
问题分析及优化
1.数组用了一次就不能用了,复用性差
2.使用算法改为一个环形的队列,取模,%
数组模拟环形队列
大部分同上,但对于上述方法做了一定的优化
思路
1.front指向队列第一个元素,即队列第一个元素为arr[front]
front初始值=0
2.rear指向队列的最后一个元素的后一个位置---留出一个空间做约定判定为空的约定,若不留空间,则可能会导致rear=front=0判定为满
rear初始值=0
3.当队列满时,条件为 (rear+1)%maxSize=front【满】
4.对列为空的条件,rear==front【空】
5.有效数据个数(rear+maxSize-front)%maxSize
6.可直接在原本代码中修改然后得到环形队列
import java.util.Scanner;
public class CircleQueue {
public static void main(String[] args) {
/*创建一个队列*/
CircleArrayQueue arrQueue = new CircleArrayQueue(4);
/*接收用户输入*/
char key = ' ';
Scanner sc = new Scanner(System.in);
boolean loop = true;
/*输出一个菜单*/
while (loop) {
System.out.println("s(show)\t");
System.out.println("e(exit)\t");
System.out.println("a(add)\t");
System.out.println("g(get)\t");
System.out.println("h(head)\t");
key = sc.next().charAt(0);
switch (key) {
case 's':
arrQueue.showQueue();
break;
case 'a':
System.out.print("please input:>");
int value = sc.nextInt();
arrQueue.addQueue(value);
break;
case 'g':
try {
int res = arrQueue.getQueue();
System.out.printf("you get %d\n", res);
} catch (Exception e) {
System.out.printf(e.getMessage());
}
break;
case 'h':
try {
int res = arrQueue.headQueue();
System.out.printf("the head is %d\n", res);
} catch (Exception e) {
System.out.printf(e.getMessage());
}
break;
case 'e':
sc.close();
loop = false;
System.out.println("程序结束");
break;
default:
break;
}
}
}
static class CircleArrayQueue {
/**
* 最大容量
*/
private int maxSize;
/**
* 队头与队尾
*/
private int front;
private int rear;
/**
* 存放数据,模拟队列
*/
private int[] arr;
/**
* 创建队列的构造器
*/
public CircleArrayQueue(int arrMaxSize) {
maxSize = arrMaxSize;
arr = new int[arrMaxSize];
/*指向队列头部的前一个位置*/
front = 0;
/*指向队列尾部的数据(队列最后一个数据)*/
rear = 0;
}
/**
* 判断队列是否满
*/
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("队列空");
}
front++;
/*1.先把front对应的值保留到一个临时变量
* 2.将front后移,考虑取模
*3.将临时存储变量返回
*/
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
/**
* 显示队列所有数据
*/
public void showQueue() {
if (isEmpty()) {
System.out.println("队列空");
return;
}
/*
*应该从front开始遍历,并且大小应该为有效数据个数,i也应取模后得到真实下标
*/
for (int i = front; i < front + size(); i++) {
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i]);
}
}
/*求出当前队列有效数据个数*/
public int size() {
return (rear + maxSize - front) % maxSize;
}
/*显示队列头数据*/
public int headQueue() {
if (isEmpty()) {
/*抛出异常*/
throw new RuntimeException("队列空");
}
return arr[front];
}
}
}