队列
队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作
简而言之,就是遵循先入先出原则。
数组模拟队列
队列是一个有序列表,可以用数组或是链表来实现
特点:遵循先入先出的原则。先存入队列的数据,要先取出,后存入的要后取出。
数组模拟队列思路
队列本身是有序列表,使用数组的结构来存储队列的数据
因为队列的输出、输入是分别从头部尾部来处理,因此需要两个变量 front 和 rear 分别记录队列头部尾部的下标,front 会随着数据输出而改变,而 rear 则是随着数据的输入而改变
代码实现
public class ArrayQueue{
private int maxSize;//最大容量
private int front;//头指针
private int rear;//尾指针
private int[] arr;//底层数组
public ArrayQueue(int maxSize){
this.maxSize = maxSize;
arr = new int[maxSize];
this.front == -1;
this.rear == -1
}
//判断队列是否已满
public boolean isFull(){
return rear == manSize - 1;
}
//添加元素
public addQueue(int n){
//先判断队列满了没
if(isFull()){
throw new RuntimeException("队列已满");
}
rear++;//尾指针+1
arr[rear] = n;//赋值
}
//判断队列是否为空
public boolean isEmpty(){
return rear == front;
}
}
//取数据
public int get(){
if(isEmpty()){
throw new RuntimeException("队列为空,不能取数据");
}
front++;
return arr[front];
}
//显示队列的所有数据
public void showQueue(){
//判断队列是否空
if (isEmpty()) {
//通过抛出异常
throw new RuntimeException("队列为空,不能取数据!");
}
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];
}
思考问题
此队列有以下问题
- 数组不能得到充分利用,使用了一次就不能复用
- 将这个数组使用算法,改进成一个环形数组 取模 %
数组模拟环形队列
优化思路
- front变量的含义做一个调整 front指向队列的第一个元素,也就是说arr[front] 就说队列的第一个元素,front的初始值=0
- rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定,rear的初始值=0
- 当队列满时,条件是 (rear+1)% maxSize = front【满】
代码实现
/**
* 使用数组模拟队列-编写一个ArrayQueue类
*/
class CircleArray {
/**
* 表示数组的最大容量
*/
private int maxSize;
/**
* front变量的含义做一个调整 front指向队列的第一个元素,
* 也就是说arr[front] 就说队列的第一个元素,front的初始值=0
*/
private int front;
/**
* rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置,
* 因为希望空出一个空间作为约定,rear的初始值=0
*/
private int rear;
/**
* 用于存放数据,模拟队列
*/
private int[] arr;
/**
* 创建队列的构造器
*/
public CircleArray(int arrManSize){
maxSize = arrManSize;
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()) {
throw new RuntimeException("队列已满,不能加了!");
}
//让rear后移
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()) {
//通过抛出异常
throw new RuntimeException("队列为空,不能取数据!");
}
//思路:从front开始遍历,遍历多少个元素
//
for (int i = front;i<front+size();i++) {
System.out.printf("arr[%d] = %d\n",i%maxSize,arr[i%maxSize]);
}
}
/**
* 求出当前队列有效数据的个数
*/
public int size(){
//rear = 1
//front = 2
//maxsize = 3
return (rear + maxSize - front) % maxSize;
}
/**
* 显示队列的头数据,注意不是取出数据
*/
public int headQueue(){
//判断是否为空
if (isEmpty()) {
//通过抛出异常
throw new RuntimeException("队列为空,不能取数据!");
}
return arr[front];
}
}