前两篇文章介绍了栈,接下来介绍队列,和栈一样,队列也有两种存储结构,顺序队列和链式队列,本文介绍顺序队列。
队列的顺序存储结构称为顺序队列,顺序队列实际上是运算受限的顺序表,顺序队列需要头指针(front)和尾指针(rear)分别指向队头和对尾,根据队列的性质(FIFO),当进行入队操作时,从队尾增加,队尾指针加一(rear=rear+1),当进行出对操作时,返回队头元素并且队头指针加一(front=front+1)。
在这里引出队列的假溢出的概念,队列的假溢通常表现在队头指针只增不减或队尾指针只减不增,致使头指针与尾指针相等,此时队列为空,但是不能再进行入队操作称为假溢出。
解决假溢出的方法有很多,如固定队首指针,出队操作后,移动所有元素后,修改队尾指针,这种方法虽然能够解决假溢出,但是会造成大量的元素移动,现在解决假溢出较好的办法是使用循环队列。
假设循环队列的向量空间为n,只要在入队时将队首和队尾的指针对n做求模运算即可实现队首和队尾指针的循环,即队首和队尾的指针取值范围都是0——n-1之间。
但是循环队列又有一个新的问题,当头尾指针相遇,即相等的时候,不能判定队列是空还是满。
解决办法是让front指向刚刚出队元素的位置,rear执行刚刚入队元素的位置,在入队操作时,先不修改队尾指针rear的值,而是首相判断(rear+1)%maxsize=front,如果相等则代表队满(此时实际上还有front指向的空闲位置),出队时,如果front=rear成立则代表队空,否则执行出队操作。另一种办法就是设置一个标识队中元素个数的变量,付出的代价就是每次入队出队操作都要修改。
java代码实现循环队列:
public class Squeue {
private static final int defaultSize = 10;
private int size;
private int front;
private int rear;
private Object[] listArray;
public Squeue(){
this.size = defaultSize + 1;
front = rear = 0;
listArray = new Object[this.size];
}
public Squeue(int size){
this.size = size + 1;
front = rear = 0;
listArray = new Object[this.size];
}
public void clear(){
front = rear = 0;
}
public void enequeue(Object object){
if((rear+1)%size != front){
rear = (rear +1)%size;
listArray[rear] = object;
}else{
System.out.println("队列满!");
}
}
public Object dequeue(){
if(!isEmpty()){
front=(front+1)%size;
return listArray[front];
}else{
System.out.println("队列为空!");
return null;
}
}
public boolean isEmpty(){
return front == rear;
}
}