循环队列
一、关于循环队列
首先要确定的是,循环队列与一般队列相同,仍然是基于数组实现的,使用一组地址连续的存储单元依次存放队头到队尾的元素。通俗来说,循环队列可看作单向队列拉成一个环,如下图所示:
在普通顺序队列中,入队操作就是先将尾指针tail右移一个单位,然后将元素值赋值给tail单位。出队时,则是头指针head后移一个单位。像这样进行了一定数量的入队和出队操作后,可能会出现“假溢出”现象,具体是:尾指针tail已指到数组的最后的一个元素(Tail==MaxLen-1),此时数组的前面部分可能还有很多闲置空间,即这种溢出并非是真的没有可用的存储空间,故称这种溢出现象为“假溢出”。为了解决这个问题,循环列表应运而生。
二、循环队列的实现
在循环队列中,入队和出队操作可看做头指针和尾指针相互追赶,当Tail追到Head就表示队列已经满了,当Head追上Tail就表示队列已经空了。
实现循环队列最关键的部分是确定队列何时为空何时满。循环队列满的判断条件与非循环队列不同,代码如下:
if ((tail + 1) % TOTAL_SPACE == head) {
System.out.println("Queue full.");
return;
} // Of if
循环队列空的判断条件与非循环队列一样,代码如下:
if (head == tail) {
System.out.println("No element in the queue");
return -1;
} // Of if
在循环意义下,入队和出队时头指针和尾指针的+1运算通常用求模运算来实现,代码如下:
data[tail % TOTAL_SPACE] = paraValue;
tail++;
int resultValue = data[head % TOTAL_SPACE];
head++;
三、代码与数据测试
package datastructure.queue;
/**
* Circle int queue
*
* @auther Weijie Pu weijiepu@163.com.
*/
public class CircleIntQueue {
/**
* The total space. One space can never be used.
*/
public static final int TOTAL_SPACE = 10;
/**
* The data.
*/
int[] data;
/**
* The index for calculating the head. The actual head is head % TOTAL_SPACE.
*/
int head;
/**
* The index for calculating the tail;
*/
int tail;
/**
* The constructor
*/
public CircleIntQueue() {
data = new int[TOTAL_SPACE];
head = 0;
tail = 0;
} // Of the first constructor
/**
********************
* Enqueue.
*
* @param paraValue
* The value of the new node.
********************
*/
public void enqueue(int paraValue) {
if ((tail + 1) % TOTAL_SPACE == head) {
System.out.println("Queue full.");
return;
} // Of if
data[tail % TOTAL_SPACE] = paraValue;
tail++;
} // Of enqueue
/**
********************
* Dequeue.
*
* @return The value at the head.
********************
*/
public int dequeue() {
if (head == tail) {
System.out.println("No element in the queue");
return -1;
} // Of if
int resultValue = data[head % TOTAL_SPACE];
head++;
return resultValue;
} // Of dequeue
/**
***********************
* Overrides the method claimed in Object, the superclass of any class.
***********************
*/
public String toString() {
String resultString = "";
if (head == tail) {
return "empty";
} // Of if
for (int i = head; i < tail; i++) {
resultString += data[i % TOTAL_SPACE] + ", ";
} // Of for i
return resultString;
} // Of toString
/**
********************
* The entrance of the program.
*
* @param args
* Not used now.
********************
*/
public static void main(String args[]) {
CircleIntQueue tempQueue = new CircleIntQueue();
System.out.println("Initialized, the list is: " + tempQueue.toString());
for (int i = 0; i < 5; i++) {
tempQueue.enqueue(i + 1);
} // Of for i
System.out.println("Enqueue, the queue is: " + tempQueue.toString());
int tempValue = tempQueue.dequeue();
System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());
for (int i = 0; i < 6; i++) {
tempQueue.enqueue(i + 10);
System.out.println("Enqueue, the queue is: " + tempQueue.toString());
} // Of for 1
for (int i = 0; i < 3; i++) {
tempValue = tempQueue.dequeue();
System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());
} // Of for i
for (int i = 0; i < 6; i++) {
tempQueue.enqueue(i + 100);
System.out.println("Enqueue, the queue is: " + tempQueue.toString());
} // Of for i
} // Of main
} // Of CircleIntQueue
运行结果:
总结
循环队列是解决假溢出的问题,通常把一维数组看成收尾相接。在老师的这段代码中,还有个需要注意的点,当判断队列为满时,这个队列实际存储长度为MaxLength-1,因为这里尾指针指向的是最后一个元素的下一个地址,即Tail指针指向的位置实际上是没有存储数据的,所以这里是牺牲一个存储空间来实现队满判断。
今日代码量:132
累积:1638