环形队列介绍
环形队列是一种头尾相连的结构,可以用数据或者链表来实现,本文通过数组实现。
1.队列的基本特性是先进先出,所以添加元素时尾部指针往后移,获取元素时,从队列头获取。
2.队列为空时,头尾指针都为0
添加元素时指针变化
add(1) tail 0 -> 1 head 0
add(2) tail 1 -> 2 head 0
add(3) tail 2->3 head 0
···
add(7) tail 6 ->7 head 0 此时队列满
获取元素时指针变化(接上面的数据)
get 获取元素1 head 0 -> 1
get 获取元素2 head 1 -> 2
···
get 获取元素 7 head=tail-7 此时队列为空(因为预留了一个空位给尾部指针)
一.通过数组实现环形队列
package com.structure.queue;
import java.util.Scanner;
/**
* @author zzq
* @Date 2021-07-14 17:18
*/
public class CircleQueueDemo {
public static void main(String[] args) {
System.out.println("测试环形队列----");
CircleQueue circleQueue = new CircleQueue(4);
char key = ' ';
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while(loop){
System.out.println("s(show):显示队列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加元素");
System.out.println("g(get):获取元素");
System.out.println("h(head):获取队列头元素");
key =scanner.next().charAt(0);
switch(key){
case 's':
circleQueue.showQueue();
break;
case 'a':
System.out.println("输出一个数");
int nextInt = scanner.nextInt();
circleQueue.add(nextInt);
break;
case 'g':
try {
int i = circleQueue.get();
System.out.println("得到的数据:"+i);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int i = circleQueue.getHead();
System.out.println("队列头部数据:"+i);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出");
}
}
class CircleQueue{
/**
* 存放元素的数组
*/
private int[] arr;
/**
* 数组大小,即最大元素个数
*/
private int maxSize;
/**
* 头部指针,指向队列的第一个元素
*/
private int head;
/**
* 尾部指针,指向最后一个元素的后一个位置
* 这里做一个约定,就是我们队列最后会留一个位置出来,用于记录这个tail的指针
* lg:
* 1.队列长度为8,实际最多能存储7个元素,因为要留一个位置给tail的指针
* 2.初始时,head=tail=0
*/
private int tail;
/**
* 初始化一个队列
* @param maxSize
*/
public CircleQueue(int maxSize) {
this.maxSize = maxSize;
this.arr = new int[maxSize];
//这里head=tail=0 不写了,因为int类型的默认值就是0
}
/**
* 判断队列是否为空,当头部和尾部指针重合时,队列为空
* @return
*/
public boolean isEmpty(){
return head == tail;
}
/**
* 队列是否满
* 因为是一个环形队列,所以正常情况下tail 在 head 的前一个位置的时候说明队列满了
* 因为是环形队列,所以要跟maxSize取模
* (tail + 1) % maxSize == head
* @return
*/
public boolean isFull(){
return (tail + 1) % maxSize == head;
}
/**
* 添加元素,尾部指针移动
* @param ele
*/
public void add(int ele){
if(isFull()){
System.out.println("队列已满,加不进去");
return;
}
//此处不能直接tail++,因为是环形队列,直接++可能会导致下标越界
//想象一下,此时head=6,tail=7 加一个元素tail++=8 会越界,那么要重新从0开始算下标
arr[tail] = ele;
tail = (tail+1) % maxSize;
}
/**
* 先进先出,从头部取数据
* @return
*/
public int get(){
if(isEmpty()){
throw new RuntimeException("队列是空的");
}
int value = arr[head];
head = (head+1) % maxSize;
return value;
}
/**
* 获取队列中实际的元素个数,因为留了一个空位,比如队列长度为8,填满时实际元素只有7个
* @return
*/
public int getSize(){
//这里加上tail-head+maxSize 加maxSize是因为有时候 tail不一定比head大
// 出现特殊情况比如多去存取之后, tail=1 head=2
return (tail-head+maxSize) % maxSize;
}
public void showQueue(){
if(isEmpty()){
System.out.println("队列为空,没有数据");
return;
}
for (int i = head; i < head+getSize(); i++) {
System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]);
}
}
public int getHead(){
if(isEmpty()){
throw new RuntimeException("队列是空的");
}
return arr[head];
}
}
运行示例