一、队列的定义
- 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素成为出队。因为队列只允许在一段插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。
二、队列的链表实现
- 用链表实现队列时,应指定一个头引用和一个尾引用,头引用指向队首,尾引用指向队尾,另外增加一个元素计数器。
三、实现步骤(重点)
- 1.定义一个结点类LinearNode.java,用于构造链表。
public class LinearNode<T> {
//指向下一个节点
private LinearNode<T> next;
//本节点存储的元素
private T element;
/**
* 创建一个空的节点
*/
public LinearNode() {
next = null;
element = null;
}
/**
* 创建一个节点存储指定元素
*
* @param elem要存储的元素
*/
public LinearNode(T elem) {
next = null;
element = elem;
}
/**
* 返回下一个节点
*
* @return 下一个节点
*/
public LinearNode<T> getNext() {
return next;
}
/**
* 设置下一个节点
*
* @param node要设置的节点
*/
public void setNext(LinearNode<T> node) {
next = node;
}
/**
* 返回节点所指向的内容
*
* @return 存储在该节点下的内容
*/
public T getElement() {
return element;
}
/**
* 设置节点所存储的内容
*
* @param elem将要存储到节点的内容
*/
public void setElement(T elem) {
element = elem;
}
}
- 2.定义队列接口,Queue.java:
public interface QueueADT<T> {
//入队
public void enqueue(T element);
//出队
public T dequeue();
//查看队首元素
public T first();
//判断队是否为空
public boolean isEmpty();
//确定队内元素
public int size();
}
- 3.定义LinkedQueue.java实现QueueADT接口,并实现其所有方法。
public class LinkedQueue<T> implements QueueADT<T> {
//元素计数器
private int count;
//定义一个头引用和尾引用
private LinearNode<T> head, tail;
public LinkedQueue() {
count = 0;
head = tail = null;
}
@Override
/**
* 1.从链表的末端添加元素,如果链表为空,则head引用也要设置为指向该新元素(唯一元素)
* 2.将当前末端元素(tail引用)的next引用设置为指向新元素
* 3.重新把tail引用设置为指向新添加的末元素
* 4.递增元素计数器
*/
public void enqueue(T element) {
LinearNode<T> node = new LinearNode<>(element);
if (isEmpty()) {
head = node;
} else {
tail.setNext(node);
}
tail = node;
count++;
System.out.println("count:" + count);
}
@Override
/**
* 1.确保队列不为空
* 2.设置一个临时引用等于栈顶元素
* 3.设置head引用为队头元素的next引用
* 4.递减元素计数器
* 5.如果队列为空,将tail引用设置为null
*/
public T dequeue() throws EmptyCollectionException {
if (isEmpty())
throw new EmptyCollectionException("queue");
T result = head.getElement();
head = head.getNext();
count--;
if (isEmpty())
tail = null;
return result;
}
@Override
public T first() {
return head.getElement();
}
@Override
public boolean isEmpty() {
if (count == 0) {
return true;
} else {
return false;
}
}
@Override
public int size() {
return count;
}
//遍历队内元素
public void syso() {
LinearNode<T> next = head.getNext();
while (next != null) {
System.out.println(next.getElement());
next = next.getNext();
}
}
}
- 4.定义异常类,当队为空时,抛出异常。
public class EmptyCollectionException extends RuntimeException {
public EmptyCollectionException(String collection) {
super("the" + collection + "is empty");
}
}
四、队列的数组实现
- 定义一个环形数组(即数组的最后一个索引后面跟的是第一个索引),定义一个整数值front,表示是队首首元素的存储位置;另一个整数值rear表示数组的下一个可用单元,还需定义整数值count用于元素计数。
- 当front或rear的值到达最后一个索引时,应使它们的值变成第一个索引,可用此方法更新其值:rear = (rear + 1) % queue.length;
五、实现步骤
-定义CircularArrayQueue类实现QueueADT接口并实现其方法
public class CircularArrayQueue<T> implements QueueADT<T> {
//数组容量
private final int DEFAULT_CAPACITY = 100;
// front:首元素存储的位置,rear:下一个可用单元,count:元素计数器
private int front, rear, count;
private T[] queue;
/**
* 创建一个指定容量的队列
*
* @param initialCapacity
*/
public CircularArrayQueue(int initialCapacity) {
front = rear = count = 0;
queue = (T[]) (new Object[initialCapacity]);
}
public CircularArrayQueue() {
front = rear = count = 0;
queue = (T[]) (new Object[DEFAULT_CAPACITY]);
}
@Override
/**
* 1.数组满时,扩充数组的容量
* 2.入队
* 3.正确更新rear的值
* 4.递增元素计数器
*/
public void enqueue(T element) {
if (size() == queue.length) {
expandCapacity();
}
queue[rear] = element;
rear = (rear + 1) % queue.length;
count++;
}
/**
* 当数组容量不够时,扩充数组,切记,已有数组的元素必须按照其在队列中的正确顺序(而不是它们出现在数组 中的顺序)复制到新数组中。
*/
private void expandCapacity() {
T[] larger = (T[]) (new Object[queue.length * 2]);
for (int scan = 0; scan < count; scan++) {
larger[scan] = queue[front];
front = (front + 1) % queue.length;
}
front = 0;
rear = count;
queue = larger;
}
@Override
/**
* 1.确保队列不为空
* 2.定义一个临时变量来存储队首元素
* 3.出列一个,将位置空出一个
* 4.更新front的值
* 5.递减元素计数器,返回队首元素
*/
public T dequeue() {
if (isEmpty()) {
throw new EmptyCollectionException(" queue ");
}
T result = queue[front];
queue[rear] = null;
front = (front + 1) % queue.length;
count--;
return result;
}
@Override
public T first() {
return queue[front];
}
@Override
public boolean isEmpty() {
if (count == 0) {
return true;
} else {
return false;
}
}
@Override
public int size() {
return count;
}
}