队列的描述
队列是基于先进先出(FIFO)或后进后出(LILO)的特殊的线性表,是应用非常广泛且极为重要的线性结构。其插入操作只允许在表尾进行,而删除操作却只能在表头进行。
顺序队列
与顺序栈相似,同样的需要分配一块连续的地址作为存储区域来依次存放队列中的从队首到队尾的元素。在这里使用一维数组存储同时用front和rear分别指向队首元素和队尾元素。
由于队列进出会使得一种“假溢出”的情况,如(d),再次入队列会使得程序报数组下标越界异常但队列实际上还有两个空的存储单元。解决这一问题可利用求模运算实现,令rear = (rear+1) % maxSize,其中,maxSize代表队列长度。即可以将顺序队列看成一种循环队列,因为rear始终指向队尾元素下一个存储单元,因此队列满的判断条件是front == rear。为以示队列为空有同样的判断条件,这里使用的是少用一个存储单元,这样可使得队列满的判断条件变为:front == (rear+1)%maxSize
几种常见的循环队列操作方法
public class CircleSqQueue
void clean(); //队列清空
boolean isEmpty(); //判断队列是否为空
int size(); //判断队列元素个数
Object peek(); //取队首元素并返回其值
Object poll(); //移除队首元素并返回其值
void offer(Object x); //将元素x入队列
具体实现:
package QueueDemo;
public class CircleSqQueue {
private Object[] queueElem; //队列的存储空间
/**
* 队首的引用
* 若队列不为空,指向队首元素
*/
private int front;
/**
* 队尾的引用
* 若队列不为空,指向队尾元素的下一个存储位置
*/
private int rear;
//循环队列的构造函数
public CircleSqQueue(int maxSize) {
front = rear = 0; //队首、队尾初始化为0
queueElem = new Object[maxSize]; //为队列分配maxSize个存储单位
}
//队列置空
public void clean() {
front = rear = 0;
}
//判断队列是否为空
public boolean isEmpty() {
return front == rear;
}
//求队列的长度
public int size() {
return(rear-front+queueElem.length)%queueElem.length;
}
//读取队首元素
public Object peek() {
if(front==rear) {
return null;
}
else {
return queueElem[front];
}
}
//入队
public void offer(Object x) throws Exception{
//判断队列是否满
if((rear+1)%queueElem.length==front) {
throw new Exception("队列已满");
}
else {
queueElem[rear] = x; //x存入rear所指的数组存储位置,使其成为新的队尾元素
rear = (rear+1) % queueElem.length;
}
}
//出队
public Object poll() {
//判断队列是否为空
if(front == rear) {
return null;
}
else {
Object t = queueElem[front];
front = (front+1) % queueElem.length; //front指向数组下一个存储位置
return t;
}
}
public void display() {
if(!isEmpty()) {
for(int i=front;i!=rear;i = (i+1) % queueElem.length) {
System.out.print(queueElem[i].toString()+" ");
}
}
else {
System.out.println("此队列为空");
}
System.out.println();
}
}
链队列
使用的是不带头结点的单链表表示,front和rear分别指向队首元素和队尾元素的结点。
几种常见的链队列操作方法
public class LinkQueue <T>
void clean(); //队列清空
boolean isEmpty(); //判断队列是否为空
int size(); //判断队列元素个数
T peek() //取队首元素并返回其值
Tpoll(); //移除队首元素并返回其值
void offer(T x); //将元素x入队列
具体实现:
入队
public void offer(T x) {
Node<T> p = new Node<T>(x); //初始化新节点
if(front != null) { //队列非空
rear.next = p;
rear = p; //改变队尾位置
}
else {
front = rear = p;
}
}
其他操作
/**
* 队首的引用
* 若队列不为空则指向队首元素
*/
public Node<T> front;
/**
* 队尾的引用
* 若队列不为空则指向队尾元素的下一个存储单位
*/
public Node<T> rear;
//链队列构造函数
public LinkQueue() {
front = rear = null;
}
//创建n个存储单位的链表队列
public LinkQueue(int n) {
Scanner sc = new Scanner(System.in);
System.out.println("请分别输入队列数据:");
for(int i=0;i<n;i++) {
offer((T)sc.next());
}
}
//队列置空
public void clear() {
front = rear = null;
}
//队列判空
public boolean isEmpty() {
return front == null;
}
//求队列的长度
public int size() {
Node<T> p = front;
int size= 0;
while(p!=null) {
p = p.next; //指针下移
size++; //计数器加一
}
return size;
}
//取队首元素
public T peek() {
if(front != null) { //队列非空
return front.data; //返回队首结点的数据取值
}
else {
return null;
}
}
//出队
public T poll() {
if(front != null) { //队列非空
Node<T> p = front; //p指向队首结点
front = front.next; //队首结点出列
if(p == rear) //被删除的结点是队尾结点时
rear = null;
return p.data; //返回队首节点的数据域值
}
else
return null;
}
//遍历并输出
public void display() {
Node<T> temp = front;
while(temp!=rear) {
System.out.print(temp.data+" ");
temp = temp.next; //首结点
}
System.out.println();
}