什么是循环队列
顺序队列在操作时容易暴露假溢出现象,为了解决假溢出现象,我们引入了循环队列,那我们应该怎么理解循环队列呢?
- 循环队列是把顺序队列首尾相连,把存储队列元素的表从逻辑上看成一个环,称为循环队列
2.添加一个元素:(queue.rear+1) % queue.length //为什么取余?
3.删除一个元素:(queue.front+1) % queue.length
4.判断队列是否满:(queue.rear+1) % queue.length == queue.front
5.判断队列是否为空:queue.front == queue.rear
我们仔细观察一下图,当rear指针在下标6时,如果放在顺序队列是无法操作的,在循环队列中我们可以让他重新返回下标为1的位置,当read=6时,rear+1 = 7 % 7 = 0,我们这样操作只会让头尾指针在索引为6时跳转到0,并不会影响其他索引,比如front + 1 = 4 % 7 = 4,所以说取模操作可以方便快捷的使其成环
那么判断队列是否已满为什么那么操作呢?
在顺序队列中判空操作的是 if(头指针==尾指针),判断是否已满操作是if(头指针-尾指针 == 数组长度 ),但是在循环数组中可能会出现尾指针在头指针前,这是再相减不能返回正确的结果,因此我们这里采用当队列添加元素到rear的下一个元素是head的时候,也就是转圈子要碰头了,我们就认为队列满了
循环队列操作
1.自定义循环队列结构
class Queue{
public int[] arr;
int front;//头指针
int rear;//尾指针
int length;//记录数组长度
}
2.队列初始化
public Queue InitQueue(int maxsize){
Queue queue = new Queue();
queue.arr = new int[maxsize];
queue.front = 0;
queue.rear = 0;
queue.length = maxsize;
return queue;
}
3.判断队列是否为空
/*
* 判断队列是否为空,只需要判断头尾指针是否相同即可
* 1为空,0不为空
* */
public int emptyQueue(Queue queue){
if (queue.front == queue.rear){
return 1;
}
return 0;
}
4.判断队列长度
/*
* 在顺序队列时,我们要获取队列所有数据的长度,只要使头指针减尾指针即可
* 但是在循环队列时,无法判断是头指针在前还是尾指针在前
* 因此我们只要使两个指针相减,加上数组长度后取模即可得到数据长度
* 如图所示
* (6-3+7)%7 = 3
* */
public int length(Queue queue){
return ((queue.rear - queue.front + queue.length) % queue.length);
}
5.队列入队
/*
* 首先判断队列是否已满,如果满返回0
* 使rear所指索引=data
* rear移向下一位,如果移动到下一位后取余数组长度为0,相当于转了一圈从头开始
* */
public int EnQueue(Queue queue,int data){
if ((queue.rear+1) % queue.length == queue.front) return 0;
queue.arr[queue.rear] = data;
queue.rear = (queue.rear+1) % queue.length;
return 1;
}
6.队列出队
/*
* 首先判断队列是否为空,如果空返回0
* 和入队是语句一样,如果移动到下一位后取余数组长度为0,相当于转了一圈从头开始
* 返回出队的值
* */
public int DeQueue(Queue queue){
if (queue.rear == queue.front) return 0;
int x = queue.arr[queue.front];
queue.front = (queue.front+1) % queue.length;
return x;
}
7.取队头元素
/*
* 先判断队列是否为空,如果队列不为空,返回头指针所指元素
* 因为不移动头指针,所以只会返回头指针的值,不会改变队列的值
* */
public int GetHead(Queue queue){
if (queue.front != queue.rear) return queue.arr[queue.front];
return 0;
}
QueueDemoTest
public class QueueDemoTest {
public static void main(String[] args) {
QueueDemo queueDemo = new QueueDemo();
Queue queue = queueDemo.InitQueue(7);
queueDemo.EnQueue(queue,10);
queueDemo.EnQueue(queue,20);
queueDemo.EnQueue(queue,30);
queueDemo.EnQueue(queue,40);
System.out.println(queueDemo.length(queue));
System.out.println(queueDemo.GetHead(queue));
System.out.println(queueDemo.emptyQueue(queue));
queueDemo.DeQueue(queue);
System.out.println(queueDemo.length(queue));
System.out.println(queueDemo.GetHead(queue));
}
}
class QueueDemo{
/*
* 初始化队列
* 头指针与尾指针相同,length属性记录数组长度
* */
public Queue InitQueue(int maxsize){
Queue queue = new Queue();
queue.arr = new int[maxsize];
queue.front = 0;
queue.rear = 0;
queue.length = maxsize;
return queue;
}
/*
* 判断队列是否为空,只需要判断头尾指针是否相同即可
* 1为空,0不为空
* */
public int emptyQueue(Queue queue){
if (queue.front == queue.rear){
return 1;
}
return 0;
}
/*
* 在顺序队列时,我们要获取队列所有数据的长度,只要使头指针减尾指针即可
* 但是在循环队列时,无法判断是头指针在前还是尾指针在前
* 因此我们只要使两个指针相减,加上数组长度后取模即可得到数据长度
* 如图所示
* (6-3+7)%7 = 3
* */
public int length(Queue queue){
return ((queue.rear - queue.front + queue.length) % queue.length);
}
/*
* 首先判断队列是否已满,如果满返回0
* 使rear所指索引=data
* rear移向下一位,如果移动到下一位后取余数组长度为0,相当于转了一圈从头开始
* */
public int EnQueue(Queue queue,int data){
if ((queue.rear+1) % queue.length == queue.front) return 0;
queue.arr[queue.rear] = data;
queue.rear = (queue.rear+1) % queue.length;
return 1;
}
/*
* 首先判断队列是否为空,如果空返回0
* 和入队是语句一样,如果移动到下一位后取余数组长度为0,相当于转了一圈从头开始
* 返回出队的值
* */
public int DeQueue(Queue queue){
if (queue.rear == queue.front) return 0;
int x = queue.arr[queue.front];
queue.front = (queue.front+1) % queue.length;
return x;
}
/*
* 先判断队列是否为空,如果队列不为空,返回头指针所指元素
* 因为不移动头指针,所以只会返回头指针的值,不会改变队列的值
* */
public int GetHead(Queue queue){
if (queue.front != queue.rear) return queue.arr[queue.front];
return 0;
}
}
class Queue{
public int[] arr;
int front;//头指针
int rear;//尾指针
int length;
}