总结一下:
一个环形队列中,有如下元素:
属性:
- 队列最大长度 ———maxSize
- 队列头———front
- 队列尾———rear
- 存放队列的数组———arr[]
方法:
- 队列构造函数———public CirclrQueue(int _maxSize)
- 判断队列为空的方法———public void isEmpty()
- 判断队列为满的方法———public void isFull()
- 返回队列最大长度的方法———public int validLength()
- 往队列里添加数据方法———public void addQueue()
- 取出队列数据方法———public int getQueue()
- 返回队列头方法———public int headQueue() (注意,只是返回队列头的副本,队列不改变)
- 展示队列方法———public void show()
废话不多说,直接上代码
public class CircleQueue {
int maxSize;//队列最大长度
int rear;//指向队列最后一个元素的后一个,这里希望预留一个空间,即rear指向的空间是不存数据的,但front指向的空间存了数据
//预留一个空间的原因是为了防止为空和为满的判定重复
int front;//指向队列的第一个元素
int [] arr ;
public CircleQueue(int _maxSize){
maxSize = _maxSize;
rear = 0;
front = 0;
arr = new int [maxSize];
}
public boolean isFull(){
return (rear + 1 )% maxSize == front;
/*
这里为什么要取模呢?
首先如果rear不是在队列的末尾时,其实是不需要取模的,
因为直接有rear + 1 == front可以判定队列为满
但如果当rear处于队列的末尾时,即rear = maxSize - 1,front = 0时,这里(rear + 1) % maxSize = 0 = front
这样就可以判定队列满
另外我们这里的队列满的定义是指队列中存了maxSize - 1个数据,而不是maxSize个数据,因为rear指向的空间并没有存入数据
*/
}
public boolean isEmpty(){
return rear == front;
/*
首先确定队列是怎么为空的
1.队列一开始就为空,没有存入数据,此时就有rear == front 判断队列为空,因为rear和front初始化都为0
2.数据一直出队列,即front一直向后移,当front指向rear前面一个位置时,即front = rear - 1
此时队列还是存在数据的,因为front指向的空间还存了一个数据
这是我们一开始就定义好的,rear指向的空间不存数据,front指向的空间存数据,之后front再后移,此时front = rear,
并且front指向的指向的最后一个数据出队列,此时队列无数据,队列为空
*/
}
public int validLength(){
return (rear + maxSize -front) % maxSize;
/*
这里的方法返回队列的有效长度
虽然式子看起来挺长的,但让我们来分情况来看(注意:我们这里是环形队列,所以有可能出现rear在front前面的情况)
1.当front在rear前面(也就是普通的情况)
此时队列的有效长度其实就可以用rear - front 表示,但上述的式子也可以表示,之所以用上述式子是因为另一种情况
2.当front在rear后面
这里的rear - front就为负数了,并且它的绝对值表示的也不是队列的有效长度,而是队列的中未存入数据的长度
即 未存入数据的长度 = |rear - front| = front - rear
而我们又有 有效长度 + 未存入数据的长度 = maxSize(因为队列中所有的数据只可能有这两种情况)
所以在这种情况下,有效长度 = maxSize - 未存入数据的长度 = maxSize + rear - front = rear + maxSize - front
这与我们的式子形式上非常相似了,还有最后一个问题,为什么要取模?
注意,这是front在rear后面时的情况,rear + maxSize - front 这个式子对第一种情况并不适用
所以我们取模使其能够以一个统一的形式写成
ps:
其实写这么多没什么用(-_-''),不妨用代码写出,如下:
if(rear - front >= 0){
return rear -front;
}
else {
return rear + maxSize - front
}
*/
}
public void addQueue(int data){
if(isFull()){
System.out.println("队列已满,无法添加数据");
return;
}
else {
arr[rear] = data;
rear = (rear + 1) % maxSize;
return;
}
}
public int getQueue(){
if(isEmpty()){
throw new RuntimeException("队列空,无法取出数据");
}
else {
int value;
value = arr[front];
front = (front + 1) % maxSize;
return value;
}
}
public void show(){
if(isEmpty()){
System.out.println("队列为空,没有数据");
}
else{
//这里不从0遍历到队列末尾,因为这样不知道队列头是什么,所以我们从队列头遍历完有效数据
for (int i = front; i <front + validLength() ; i ++){
System.out.printf("arr[%d] = %d\n",i % maxSize,arr[i % maxSize]);
}
}
}
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("队列空,无head");
}
else{
return arr[ front ];
}
}
}