此文章仅作为自己学习过程中的记录和总结,同时会有意地去用英文来做笔记,一些术语的英译不太准确,内容如有错漏也请多指教,谢谢!
一、概述
-循环队列的基本组成结构为:
- (int) maxSIze:队列的最大容量。
- (int) front:指向队列头的“指针”。(实际上存储的是指向队列第一个元素下标)
- (int) rear:指向队列尾的“指针”。(实际上存储的是队列最后一个元素的下一个位置的下标)
- (E[ ]) queueArr:模拟队列的数组。(E的类型取决于实际情况)
-相较于普通队列的区别:
- 队列容量:模拟普通队列的数组每个元素都被利用起来;而模拟循环队列的数组的实际有效元素个数为(maxSize - 1),有一个位置被用来对队列空/满做判断。
- front和rear的含义: 循环队列中,front存储的是队列第一个元素的下标,rear存储的是队列最后一个元素的下一位置的下标;而普通队列中,front存储的是队列第一个元素的下一位置的下标,rear存储的是队列最后一个元素的下标。
- front和rear的默认值: 循环队列中,front和rear默认值为0;而普通队列中,front和rear的默认值为-1。
(关于普通队列,具体可见:数据结构与算法–数组模拟队列(Queue))
(关于C语言描述的普通队列和循环队列,具体可见:队列的定义、顺序、循环、链队列及其部分操作具体实现(C语言描述))
-内容:
- 构造方法创建数组循环队列。
- isEmpty(), isFull()【判断队列是否为空/满】
- getSIze()【获取队列当前有效元素个数】
- addQueue()【向队列中添加元素】
- getQueue()【获取队列头元素并将front向后移一个,实现“假出队列”的效果】
- peekQueue()【获取队列头元素但不影响front的值】
- showQueue()【展示队列所有元素】
-特别说明:
- 判断循环队列是否为空的条件:rear == front
- 判断循环队列是否为满的条件:(rear + 1) % maxSize == front
- 循环队列当前有效元素个数:(rear + maxSize - front) % maxSize【可看作对rear-front取绝对值】
二、代码实现
- Attributes and constructor
/*
CircularArrayQueue
Zzay
2021/01/17
*/
package com.zzay.queue;
/**
* DIFFERENCE:
* (1) Capacity:【容量】
* The capacity of a circular array queue is actually "maxSize - 1",
* because it need to spare a space for the judgements of "isFull()" and "isEmpty()".
* (若不留一个空位,则无论是满还是空,都是"front == rear")
*
* (2) Default value of "front" and "rear":【front和rear的默认值】
* Front: Default value is now 0 in place of -1 as before.
* Rear: Default value is now 0 in place of -1 as before.
*
* (3) The meaning of "front" and "rear":【front和rear的含义】
* Front: Points to the first element of the queue, instead of the previous place of the first element.
* Rear: Points to the next place of the last element, instead of the last element.
*
* @author Zzay
* @version 2021/01/17
*/
public class CircularArrayQueue {
// The maximum capacity of the array.
private int maxSize;
// The indicator of the first element of the queue.
// The "front" indicator points right to the first element, different from the linear queue.
// Default value is 0.
private int front;
// The indicator of the rear element of the queue.
// The "rear" indicator points to the next place of the last element, different from the linear queue.
// Default value is 0.
private int rear;
// The array that modifies a queue.
private int[] queueArr;
/**
* Receive a capacity and instantiate a queue array with the max size of the same value.
* Also, do initializations.
*
* @param capacity The expected max size of the queue array
*/
public CircularArrayQueue(int capacity) {
if (capacity <= 0) {
System.out.println("Invalid capacity, enter again...");
return;
}
maxSize = capacity;
queueArr = new int[maxSize];
}
}
- Methods
/**
* Judge whether the queue is empty or not.
*
* @return True if the queue is empty; false if the queue is not empty
*/
public boolean isEmpty() {
return rear == front;
}
/**
* Judge whether the queue is full or not.
* Plus 1 because we need to spare a space for the judgment,
* or we are not able to judge whether it's full or not (Draw a graph to see),
* because no matter full or empty, there's always "front==rear".
*
* @return True if the queue is full; false if the queue is not full
*/
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
/**
* Get the current size of the queue.
*
* @return The current size of the queue
*/
public int getSize() {
return (rear + maxSize - front) % maxSize;
}
/**
* Add an element into the queue if it's not full.
*/
public void addQueue(int data) {
//Judge if the queue is full or not.
if (isFull()) {
throw new RuntimeException("The queue is full, cannot add element into it...");
}
queueArr[rear] = data;
rear = (rear + 1) % maxSize;
}
/**
* Get the first element from the queue if it's not empty.
*
* @return The first element in the queue
*/
public int getQueue() {
//Judge if the queue is empty or not.
if (isEmpty()) {
throw new RuntimeException("The queue is empty, cannot get element from it...");
}
int first = queueArr[front];
front = (front + 1) % maxSize;
return first;
}
/**
* Get the data of the first element in the queue, without affecting its existence.
*/
public int peekQueue() {
if (isEmpty()) {
throw new RuntimeException("The queue is empty, cannot peek the first element...");
}
return queueArr[front];
}
/**
* Display the data in the queue.
*/
public void showQueue() {
if (isEmpty()) {
System.out.println("The queue is empty...");
return;
}
for (int i = front; i < front + getSize(); i++) {
System.out.printf("array[%d]: %d\n", i % maxSize, queueArr[i % maxSize]);
}
System.out.println();
}
- Test
/*
CircularArrayQueueTest
Zzay
2021/01/17
*/
package com.zzay.queue;
import java.util.Scanner;
/**
* @author Zzay
* @version 2021/01/17
*/
public class CircularArrayQueueTest {
public static void main(String[] args) {
char key = ' ';
boolean loop = true;
Scanner scanner = new Scanner(System.in);
CircularArrayQueue circularArrayQueue = new CircularArrayQueue(4);
while (loop) {
System.out.println("s(show): show queue");
System.out.println("a(add): add element");
System.out.println("g(get): get first element");
System.out.println("p(peek): peek first element");
System.out.println("e(exit): exit the program");
key = scanner.next().charAt(0);
switch (key) {
case 's':
circularArrayQueue.showQueue();
break;
case 'a':
try {
System.out.println("Please enter the element you'd like to add:");
circularArrayQueue.addQueue(scanner.nextInt());
} catch (RuntimeException e) {
System.out.println(e.getMessage());
}
break;
case 'g':
try {
System.out.println("The element is: " + circularArrayQueue.getQueue());
System.out.println();
} catch (RuntimeException e) {
System.out.println(e.getMessage());
}
break;
case 'p':
try {
System.out.println("The first element is: " + circularArrayQueue.peekQueue());
System.out.println();
} catch (RuntimeException e) {
System.out.println(e.getMessage());
}
break;
case 'e':
loop = false;
break;
default:
break;
}
}
System.out.println("Thanks for your using!");
}
}