-
-
- 数组模拟队列实现
-
- 顺序队列的实现
以下采用数组实现,初始化一个队列数组的空间长度为5,队列有两个标记,一个队头的位置front,一个队尾的位置rear,初始都指向数组下标为0的位置,如图所示:
在插入元素时,rear标记递增+1,比如依次入队11,22,33这三个元素,则当前队列存储情况如图:
当前front为0,rear为3,接下来执行出队操作,此处将11元素出队,则front标记递增+1,此时队列的存储情况如图:
根据上面的图例,我们可以通过rear-front获得队列中元素的个数。当”front==rear”时,此时队列为空,而当”rear==数组长度”时,此时将无法添加元素,我们可以设为队列已满,接下来我们就通过代码实现这个操作。
【示例】顺序队列的实现
public class ArrayQueue<T> {
/**
* 模拟队列的数组
*/
private Object[] elementData;
/**
* 保存队首的指针
*/
private int front;
/**
* 保存队尾的指针
*/
private int rear;
/**
* 无参构造方法
*/
public ArrayQueue() {
// 设置数组的默认空间长度为10
this(10);
}
/**
* 有参构造方法
* @param capcaity 设置数组的空间长度
*/
public ArrayQueue(int capcaity) {
// 处理capcaity参数不合法的情况
if (capcaity < 0) {
throw new IllegalArgumentException("参数不合法异常,capcaity:" + capcaity);
}
// 创建指定空间长度的数组
this.elementData = new Object[capcaity];
}
/**
* 获取队列中元素的个数
* @return 返回队列中元素的个数
*/
public int getSize() {
return rear - front;
}
/**
* 入队列操作
* @param element
*/
public void add(T element) {
// 判断队列是否已满
if (isFull()) {
throw new RuntimeException("队列已满,无法执行入队列操作");
}
// 执行入队操作
elementData[rear++] = element;
}
/**
* 删除队列的首元素
* @return 返回被删除的元素值
*/
public T remove() {
// 判断队列是否为空
if (isEmpty()) {
throw new RuntimeException("队列为空,无法执删除队列操作");
}
// 获取队列首元素
T element = (T)elementData[front];
// 把front索引位置元素设置为默认值,并更新front索引值
elementData[front++] = null;
// 返回被删除的队首元素
return element;
}
/**
* 获得队列的首元素
* @return 返回队列的首元素
*/
public T element() {
// 判断队列是否为空
if (isEmpty()) {
throw new RuntimeException("队列为空,无法执获取队列操作");
}
// 获取并返回队列的首元素
return (T)elementData[front];
}
/**
* 判断队列是否已满
* @return 队列已满,则返回true;队列未满,则返回false。
*/
private boolean isFull() {
return rear == elementData.length;
}
/**
* 判断队列是否为空
* @return 队列为空,则返回true;队列不为空,则返回false。
*/
public boolean isEmpty() {
return front == rear;
}
} |
按照以上的操作,当front==rear时,那么队列是否已经满呢?未必!因为front和rear在入队和出队操作中只增不减,因此head和tail都会最终指向队列之外的存储位置,此时虽然数组为空,但也无法将元素入队。
如何解决这个问题,我们引入了循环队列。当rear的取值为数组空间长度,此时如果数组还有空闲的位置,将rear重新指向数组的0索引处即可,如图所示:
如果继续入队66和77这两个元素,则队列的存储结构如图:
在采用循环队列实现的过程中,当队列满队时,front等于rear,而当队列空时,front也等于rear,为了区分两种状态,一般规定循环队列的长度为”数组长度-1”,即有一个位置不放元素,此时front==rear时为空队,而当front==(rear+1)%数组长度,说明对满。
【示例】循环队列的实现
public class ArrayQueue<T> {
/**
* 模拟队列的数组
*/
private Object[] elementData;
/**
* 保存队首的指针
*/
private int front;
/**
* 保存队尾的指针
*/
private int rear;
/**
* 无参构造方法
*/
public ArrayQueue() {
// 设置数组的默认空间长度为10
this(10);
}
/**
* 有参构造方法
* @param capcaity 设置数组的空间长度
*/
public ArrayQueue(int capcaity) {
// 处理capcaity参数不合法的情况
if (capcaity < 0) {
throw new IllegalArgumentException("参数不合法异常,capcaity:" + capcaity);
}
// 创建指定空间长度的数组
this.elementData = new Object[capcaity];
}
/**
* 获取队列中元素的个数
* @return 返回队列中元素的个数
*/
public int getSize() {
if (rear >= front) {
return rear - front;
}
else {
return (rear + elementData.length) - front;
}
}
/**
* 入栈操作
* @param element
*/
public void add(T element) {
// 判断队列是否已满
if (isFull()) {
throw new RuntimeException("队列已满,无法执行入队列操作");
}
// 执行入队操作
elementData[rear] = element;
// 更新rear的值
rear = (rear + 1) % elementData.length;
}
/**
* 删除队列的首元素
* @return 返回被删除的元素值
*/
public T remove() {
// 判断队列是否为空
if (isEmpty()) {
throw new RuntimeException("队列为空,无法执删除队列操作");
}
// 获取队列首元素
T element = (T)elementData[front];
// 把front索引位置元素设置为默认值
elementData[front] = null;
// 更新front索引值
front = (front + 1) % elementData.length;
// 返回被删除的队首元素
return element;
}
/**
* 获得队列的首元素
* @return 返回队列的首元素
*/
public T element() {
// 判断队列是否为空
if (isEmpty()) {
throw new RuntimeException("队列为空,无法执获取队列操作");
}
// 获取并返回队列的首元素
return (T)elementData[front];
}
/**
* 判断队列是否已满
* @return 队列已满,则返回true;队列未满,则返回false。
*/
private boolean isFull() {
return front == (rear + 1) % elementData.length;
}
/**
* 判断队列是否为空
* @return 队列为空,则返回true;队列不为空,则返回false。
*/
public boolean isEmpty() {
return front == rear;
}
} |