用数组来实现循环队列的方式主要有两种:
1.少用一个元素空间来实现循环队列
如上图,正常情况下和第三个数组图一样,每个元素空间都有元素才算是满的,但是现在我们要少用一个元素空间,就和最后三个图一样就算循环队列满。
这样做的原因是为了区分开判断 循环队列满 和 空 的条件,避免两个条件的判断方式重复。
首先我们需要两个指针 head 和 tail 来指向头尾两个元素,head 和 tail 我们约定初始化为0,head指向头元素,tail指向尾元素的下一个元素
如上图,最开始时head=0;tail=0;当添加一个元素之后,head=0;tail=1;当循环队列一直添加元素到循环队列满时,head=0;tail=3....由此一个个类推
可以判断,当循环队列是空的时候:head=tail
当循环队列满的时候:(tail+1)%maxSize=head。
在向循环队列添加元素 enQueue 时,先判断队列是否满,满的话就添加失败,若没满,则将 tail 位置元素空间赋值,再将指针 tail后移,指向下一个位置
在从循环队列取出元素 deQueue 时,先判断队列是否空,空的话就获取失败,若非空,则直接获取到 head 位置的值,并将指针 head 后移
class ArrayCircleQueue {
private int maxSize;
private int[] arr;
private int head; // 头指针:指向头元素
private int tail; // 尾指针:指向尾元素的下一个位置
public ArrayCircleQueue(int maxSize) {
this.maxSize = maxSize;
this.arr = new int[maxSize];
this.head = 0;
this.tail = 0;
}
public boolean isEmpty() {
return head == tail;
}
public boolean isFull() {
return (tail + 1) % maxSize == head;
}
// 添加元素
public void enQueue(int element) {
if (isFull()) {
throw new RuntimeException("队列已满,无法添加元素");
}
arr[tail] = element;
tail = (tail + 1) % maxSize;
}
// 取出元素
public int deQueue() {
if (isEmpty()) {
throw new RuntimeException("队列为空,没有元素");
}
int res = arr[head];
head = (head + 1) % maxSize;
return res;
}
// 展示循环队列所有数据
public void showQueue() {
if (isEmpty()) {
System.out.println("队列为空...");
return;
}
for (int i = head; i < head + size(); i++) {
System.out.printf("arr[%d]=%s\n", i % maxSize, arr[i % maxSize]);
}
System.out.println("size :" + size());
}
// 求出当前队列有效数据
public int size() {
return (tail + maxSize - head) % maxSize;
//return tail + maxSize - head;
}
// 显示循环队列的头元素
public int showHead() {
if (isEmpty()) {
throw new RuntimeException("队列为空,没有元素");
}
return arr[head % maxSize];
}
}
2.设置一个标志位
除了第一种方法,还有一种就是采用所有的元素空间,使用一个标志位来判断循环队列是满还是空,比我有一个标志位 isfull
如上图,第三种和第五种情况下,循环队列是满的。
看图可知,当head=tail的时候,循环队列为空或者满,所以我们需要一个标志位来辅助判断。
首先,初始化的时候标志位 isfull为false
当添加元素时,我们进行判断添加完元素后,循环队列是否满了,如果满了,则将标志位设置为true
public void enQueue(int element) {
if (isFull()) {
throw new RuntimeException("队列已满,无法添加数据");
}
arr[tail] = element;
tail = (tail + 1) % maxSize;
// 添加元素后判断是否满,若满设置标志位为isfull为true
if (tail == head && isfull == false) {
isfull = true;
}
}
当取出元素时,取出一个元素后循环队列肯定不会是满的,所以直接设置标志位 isfull 为false
public int deQueue() {
if (isEmpty()) {
throw new RuntimeException("队列为空,无法获取数据");
}
int res = arr[head];
head = (head + 1) % maxSize;
// 设置循环队列标志位为false
isfull = false;
return res;
}
所以,当标志位为true的时候,队列为满,当标志位为false,且head=tail时,队列为空。
具体代码如下
class ArrayCircleQueue2 {
private int maxSize;
private int[] arr;
private int head; // 头指针:指向头元素
private int tail; // 尾指针:指向尾元素的下一个位置
private boolean isfull; // 标志位:判断环形队列是否满
public ArrayCircleQueue2(int maxSize) {
this.maxSize = maxSize;
this.arr = new int[maxSize];
this.head = 0;
this.tail = 0;
isfull = false;
}
public boolean isFull() {
return isfull;
}
public boolean isEmpty() {
return (isfull == false) && (head == tail);
}
public void enQueue(int element) {
if (isFull()) {
throw new RuntimeException("队列已满,无法添加数据");
}
arr[tail] = element;
tail = (tail + 1) % maxSize;
// 添加元素后判断是否满,若满设置标志位为isfull为true
if (tail == head && isfull == false) {
isfull = true;
}
}
public int deQueue() {
if (isEmpty()) {
throw new RuntimeException("队列为空,无法获取数据");
}
int res = arr[head];
head = (head + 1) % maxSize;
// 设置循环队列标志位为false
isfull = false;
return res;
}
public void showQueue() {
if (isEmpty()) {
System.out.println("队列为空...");
return;
}
for (int i = head; i < head + size(); i++) {
System.out.printf("arr[%d]=%s\n", i % maxSize, arr[i % maxSize]);
}
System.out.println("size :" + size());
}
// 求出当前队列有效数据
public int size() {
if(isfull){
return maxSize;
}else{
return (tail + maxSize - head) % maxSize;
}
}
public int showHead() {
if (isEmpty()) {
throw new RuntimeException("队列为空,没有元素");
}
return arr[head % maxSize];
}
}
此为个人学习记录,若有错误请各位指出。