- 队列是一种操作受限制的线性结构,遵循“先进先出”原则,即遵循FIFO(First In First Out)原则。
- 换而言之,队列只允许在其前端(head)进行删除操作(出队),而在其后端(tail)进行插入操作(入队)。进行插入操作的端称为队尾,进行删除操作的端称为队头。
顺序队列
顺序队列是基于数组实现的, 即在连续存储单元中存放队列的元素,并设置head指示器指示队头,tail指示队尾。
每次在队尾插入一个元素是,tail增1(tail++);而每次在队头删除一个元素时,head增(head++)。随着插入和删除操作的进行,队列元素的个数不断变化,队列所占的存储空间也在为队列结构所分配的连续空间中移动。
但是这种设定容易出现“假溢出”现象:由于入队和出队操作中,头尾指示器只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于向量空间的规模时,也可能由于队尾指示器已超越向量空间的上界而不能做入队操作。
循环队列
解决“假溢出”的方法是将顺序队列改为首尾相接的循环结构,这种队列就是所谓的循环队列,又称顺序循环队列。
具体操作是:无论插入或删除,一旦队尾指示器tail增1或队头指示器head增1 时超出了所分配的队列空间(capacity),就让它指向这片连续空间的起始位置。
即队头指示器head增1的操作修改为:head = (head+1)%capacity
即队尾指示器tail增1的操作修改为:tail = (tail+1)%capacity
除此之外,我们还可以用一个变量size来记录队列的长度,然后通过size和capacity(容量)的组合来判断队列的状态。
Java代码实现循环队列:
package com.guohao.arithmetics;
import java.lang.reflect.Array;
/**
* 循环顺序队列
*/
public class SeqQueue<T> {
private T[] dataArray; //存放数据的数组
private int capacity; //队列的容量
private int size; //队列的长度
private int head; //队头元素的下标
private int tail; //队尾元素的下标
public SeqQueue(Class<T> type, int capacity){
//为了保证类型安全,Java中不允许直接用泛型声明数组,如:"dataArray = new T[capacity]"是错误的!
dataArray = (T[]) Array.newInstance(type, capacity);
this.capacity = capacity;
size = 0;
head = 0;
tail = -1;
}
/**
* 入队
* @param element
* @return
*/
public boolean Enqueue(T element){
if(!isFull()){
tail = (tail+1)%capacity;
dataArray[tail] = element;
size++;
return true;
}
return false;
}
/**
* 出队
* @return
*/
public boolean Dequeue(){
if(!isEmpty()){
head = (head+1)%capacity;
size--;
}
return false;
}
/**
* 取队头元素
* @return
*/
public T peekHeadElement(){
if(!isEmpty()){
return dataArray[(head+1)%capacity];
}
return null;
}
/**
* 判断是否满队
* @return
*/
public boolean isFull(){
return size==capacity;
}
/**
* 判断是否空队
* @return
*/
public boolean isEmpty(){
return size==0;
}
//getter & setter
public T[] getDataArray() {
return dataArray;
}
public void setDataArray(T[] dataArray) {
this.dataArray = dataArray;
}
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getHead() {
return head;
}
public void setHead(int head) {
this.head = head;
}
public int getTail() {
return tail;
}
public void setTail(int tail) {
this.tail = tail;
}
}