时间过得真快距离上一篇博客稀疏数组 已经过去了许多天了,今天整理了一下队列。
01-什么是队列?
队列是一个有序列表,可以用数组或是链表来实现。
队列遵循先入先出原则: 即:先存队列的数据,要先取出。后存入的要后取出数据
02-数组模拟队列步骤:
- 定义队列的最大容量记为:maxSize。
- 定义两个变量记录队列前后端下标 分别为front(前端)、rear(后端),并且初始值都为-1。
- 为什么要定义两个变量记录队列前后端下标?
因为队列的输出输入分别从前后端处理,front会随着数据输出而改变、而rear则是随着数据输入而改变。
02-01队列中添加数据步骤:
- 判断队列是否已满
- rear指针向后移,rear+1
- 若rear指针小于队列的最大小标maxSize-1,正常存入数据,否则队列已满
02-02队列中取出数据步骤:
- 判断队列是否为空
- front指针向后移,front+1
判断队列是否已满: rear == maxSize-1
判断队列是否为空: front == rear
图解和笔记:
具体代码如下:
//操作队列的数组
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 isEmpty() {
return rear == front;
}
//判断队列中是否已满的方法
public boolean isFull() {
return rear == maxSize - 1;
}
//入队列数据的方法
public void addQueue(int num) {
if (isFull()) {
System.out.println("队列已满,不能加入~~");
return;
}
rear++;
arr[rear] = num;
}
//出队列数据方法
public int getQueue() {
//如果为空抛出异常
if (isEmpty()) {
throw new RuntimeException("队列为空,没有数据~~~");
}
front++;
return arr[front];
}
//展示队列数据
public void showQueue() {
//遍历
if (isEmpty()) {
System.out.println("队列为空,没有数据~~~");
return;
}
System.out.println(Arrays.toString(arr));
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];
}
}
编写一个界面 为用户提供选择的功能
//创建数组
ArrayQueue queue = new ArrayQueue(4);
//创建输入流对象
Scanner scanner = new Scanner(System.in);
char key = ' ';
//程序结束标记
boolean flag = true;
while (flag) {
System.out.println("a(addQueue)表示添加数据");
System.out.println("g(getQueue)表示获取数据");
System.out.println("s(showQueue)表示展示队列的数据");
System.out.println("h(headQueue)表示展示队头数据");
System.out.println("e(exit)表示退出程序");
//接收字符
key = scanner.next().charAt(0);
switch (key) {
case 'a':
System.out.println("输入一个数");
int value = scanner.nextInt();
queue.addQueue(value);
break;
case 'g':
try {
int result = queue.getQueue();
System.out.printf("取出的数据是:%d\n", result);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 's':
queue.showQueue();
break;
case 'h':
try {
int result = queue.headQueue();
System.out.printf("取出的数据是:%d\n", result);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close();
flag = false;
break;
default:
break;
}
}
出现问题及优化:
- 数组使用一次就不能用,不能达到复用。
- 数组使用算法,实现环形队列 取模: %
05-环形队列
环形队列中对上面的前端后端变量以及判断队列是否已满做出了调整。
图解:
代码如下:
class CircleQueue {
//定义数组的容量
private int maxSize;
//定义队列的头部
private int front;
//定义队列的尾部
private int rear;
//定义数组
private int[] arr;
//初始化值
public CircleQueue(int arrMax) {
maxSize = arrMax;
arr = new int[maxSize];
}
//判断队列是否为空
public boolean isEmpty() {
return front == rear;
}
//判断队列是否已满
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
//添加数据的方法
public void addQueue(int input) {
//判断队列是否已满
if (isFull()) {
System.out.println("队列已满~~~");
return;
}
arr[rear] = input;
rear = (rear + 1) % maxSize;
}
//取出数据的方法
public int getQueue() {
//判断队列是否为空
if (isEmpty()) {
throw new RuntimeException("队列为空~~~");
}
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
//显示所有队列的数据
public void showQueue() {
if (isEmpty()) {
System.out.println("队列为空,没有数据~~~");
return;
}
for (int i = front; i < front + size(); i++) {
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
}
}
//数组数据有效个数
public int size() {
//比如说 rear添加了2个数据 maxSize为4 front取出了1个数据 (2+4-1)%4==2
return (rear + maxSize - front) % maxSize;
}
//展示队列头数据
public int headQueue() {
if (isEmpty()) {
throw new RuntimeException("队列为空~~~");
}
return arr[front];
}
}
gif动图演示过程如下:
总结:
使用取模运算解决了数组复用的问题。
反思:
刚开始理解有点困难,多练几遍多想想,就发现思路很明确了。
喜欢我的文章的小伙伴一键三连哦~~