实现队列的思路
队列数据结构是动态集合的一种,它实现的是一种先进先出(first-in, first-out)FIFO策略。队列一般支持入队(enqueue),出队(dequeue)操作。实现上可以用数组A(实际上使用链表来实现队列比使用数组更优)作为栈底层数据存储,通过属性headerIndex来记录队列头(最先入队的元素)下标位置,footerIndex来记录队列尾巴(最后入队的元素)下标位置,(footerIndex - headerIndex)作为队列总元素数量(length)。
每次调用入队(enqueue)函数时,需要先判断底层数组长度是否足够容纳新的元素(A.length < footerIndex + 1),如果不够需要继续判断是否有出队,如果有出队(headerIndex > 0)可以将数组所有元素往前面(0)下标移动,如果没有出队(headerIndex = 0),可以按照给定的算法进行数组扩容。最后将元素保存到数组(footerIndex + 1)下标,然后将(footerIndex = footerIndex -1)作为队列最后入队(队列尾)下标。
每次调用出队函数时,需要先判断底层数组是否为空,如果为空则数组越界异常,否则返回headerIndex元素(FIFO),将headerIndex下标置为null,最后将(headerIndex = headerIndex + 1)作为队列最开始入队(队列头)下标。
实现队列的代码
/**
* <p>
* 数据结构 - 队列 - 先进先出(FIFO first-in first-out)
* </p>
*
* @author laizhiyuan
* @since 2019/9/25.
*/
public class Queue<T> {
private Object[] dataElement;
private int headerIndex = 0;
private int footerIndex = 0;
private static final int DEFAULT_INIT_CAPACITY = 10;
public Queue() {
this.dataElement = new Object[DEFAULT_INIT_CAPACITY];
}
public Queue(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("capacity can not than less 0");
}
this.dataElement = new Object[capacity];
}
/**
* 入队
*
* @param ele 新元素
*/
public void enqueue(T ele) {
//判断数组长度是否足够容纳新的元素
if (this.dataElement.length < (this.footerIndex + 1)) {
if (this.headerIndex > 0) {
//记录出队数量
int enqueueNum = this.headerIndex;
//如果已经出队一部分, 则把全部元素往前移动一下
System.arraycopy(this.dataElement, this.headerIndex, this.dataElement, 0, this.length());
//重新计算队列头尾下标
this.headerIndex = 0;
this.footerIndex = this.footerIndex - enqueueNum;
} else {
//如果没有任何出队,则要扩容数组长度为原来的长度+原来长度 / 2
int newLength = this.dataElement.length + (this.dataElement.length >> 1);
this.dataElement = Arrays.copyOf(this.dataElement, newLength);
}
}
//将新元素保存到(footerIndex)位置
this.dataElement[this.footerIndex++] = ele;
}
/**
* 出队
*
* @return 返回出队元素
*/
@SuppressWarnings("unchecked")
public T dequeue() {
if (this.isEmpty()){
throw new ArrayIndexOutOfBoundsException(this.length() - 1);
}
Object o = this.dataElement[this.headerIndex];
this.dataElement[this.headerIndex] = null;
this.headerIndex = this.headerIndex + 1;
return (T) o;
}
public int length() {
return this.footerIndex - this.headerIndex;
}
public boolean isEmpty() {
return this.length() <= 0;
}
测试队列代码
public static void main(String[] args) {
Queue<String> queue = new Queue<>();
System.out.println(queue.length());
System.out.println(queue.isEmpty());
//footer = 0 + 1, header=0
queue.enqueue("Q1");
//footer = 1 + 1, header=0
queue.enqueue("Q2");
queue.enqueue("Q3");
queue.enqueue("Q4");
queue.enqueue("Q5");
queue.enqueue("Q6");
queue.enqueue("Q7");
queue.enqueue("Q8");
queue.enqueue("Q9");
//footer = 9 + 1, header=0
queue.enqueue("Q10");
System.out.println(queue.length());
//value=Q1, footer = 9 + 1, header=0 + 1
System.out.println(queue.dequeue());
System.out.println(queue.length());
//注意这一步会发生移动数组元素
//因为出队一次(header > 0),且(this.dataElement.length < (this.footerIndex + 1)
queue.enqueue("Q11");
System.out.println(queue.length());
//注意这里会发生扩容
//因为footer + 1大于数组长度且header等于0
queue.enqueue("Q12");
queue.enqueue("Q13");
queue.enqueue("Q14");
queue.enqueue("Q15");
queue.enqueue("Q16");
queue.enqueue("Q17");
System.out.println(queue.length());
System.out.println(queue.isEmpty());
System.out.println(queue.dequeue());
System.out.println(queue.dequeue());
System.out.println(queue.dequeue());
System.out.println(queue.dequeue());
System.out.println(queue.dequeue());
System.out.println(queue.dequeue());
}
验证队列输出
0
true
10
Q1
9
10
16
false
Q2
Q3
Q4
Q5
Q6
Q7
虽然实现队列代码不多,但是理解队列原理和实现的思路很重要。
-END-
长按扫码关注【Java软件编程之家】公众号,一起学习,一起成长!