环形队列
环形队列是一个首尾相连的FIFO的数据结构,采用数组的线性空间,数据组织简单。能很快知道队列是否满为空。能以很快速度的来存取数据。
环形队列实现原理
本章环形队列使用数组实现,当数据到了数组尾部,利用取模的方式将转回到0的位置。由于入队时尾指针向前追赶头指针;出队时头指针向前追赶尾指针,造成队空和队满时头尾指针均相等。因此,无法通过条件front==rear来判别队列是"空"还是"满"。解决这个问题的方法有三种(使用第二种方式实现):
- 另设一布尔变量以区别队列的空和满;
- 少用一个元素的空间。约定入队前,测试尾指针在循环意义下加1后是否等于头指针,若相等则认为队满(注意:rear所指的单元始终为空);
- 使用一个计数器记录队列中元素的总数(即队列长度)。
代码实现
public class CircleArrayQueue <E>{
private int maxSize;
private int front;
private int rear;
private Object[] array;
public CircleArrayQueue(int maxSize){
// front指向第一个元素的位置。front的初始值为0。
this.front = 0;
// rear指向最后一个元素的后一个元素的位置。rear的初始值为0。
this.rear = 0;
// 由于使用第二种方案,队列允许存储的最大数量为array.length - 1 ,所以,初始化数组时使用maxSize + 1
this.maxSize = maxSize + 1;
this.array = new Object[this.maxSize];
}
/**
* 判断队列是否已满
* @return
*/
public boolean isFull(){
return (this.rear + 1) % this.maxSize == this.front;
}
/**
* 判断队列是否为空
* @return
*/
public boolean isEmpty(){
return this.rear == this.front;
}
/**
* 向队列尾加入数据
* @param e
*/
public void put(E e){
Objects.requireNonNull(e);
if (isFull()){
throw new RuntimeException("队列已满");
}
array[rear] = e;
rear = (rear + 1) % maxSize;
}
/**
* 从队列头取出数据
* @return
*/
public E get(){
if (isEmpty()){
throw new RuntimeException("队列为空");
}
E e = (E)array[front];
front = (front + 1) % maxSize;
return e;
}
/**
* 查询队列中包含的有效元素数量
* @return
*/
public int size(){
return (rear - front + maxSize) % maxSize;
}
/**
* 遍历队列
*/
public void show(){
int size = size();
for (int i = front; i < front + size; i++) {
System.out.println(array[i % maxSize]);
}
}
/**
* 查询队列头
* @return
*/
public E head(){
if (isEmpty()){
throw new RuntimeException("队列为空");
}
return (E)array[front];
}
public static void main(String[] args) {
// 创建一个队列;
char key = ' '; //接收用户输入
CircleArrayQueue<Integer> queue = new CircleArrayQueue<Integer>(4);
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':
queue.show();
break;
case 'a':
System.out.println("输出 一个数");
int value = scanner.nextInt();
try {
queue.put(value);
} catch (Exception e) {
e.printStackTrace();
}
break;
case 'g': //取出数据
try {
int res = queue.get();
System.out.printf("取出的数据是%d\n", res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'h': //查看队列头的数据
try {
int res = queue.head();
System.out.printf("队列头的数据是%d\n", res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e': //退出
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出~~");
}
}