循环队列
由于自定义的队列在出队操作时,需要将所有元素向前移动,时间复杂度为O(n),比较浪费时间,所以优化为O(1)。我们就需要用到循环队列。正所谓:"用空间换时间”。
解决方法:声明两个变量,分别指向队头和队尾。
自定义循环队列实现类
package com.company.queue;
/**
* 自定义循环队列
*
* @param <T> 泛型
* @Author: wenhua
* @CreateTime: 2023-01-07 12:28
*/
public class LoopQueue<T> implements Queue<T> {
private T[] data;
// size 表示队列长度,front 指向队列头部元素(移除元素) tail 指向队列尾部最后一个元素(添加元素)
private int size, front, tail;
public LoopQueue() {
this(5);// 调用有参构造函数,默认初始化队列长度为5
}
/**
* 有参构造函数
*
* @param capacity 队列容量
*/
public LoopQueue(int capacity) {
data = (T[]) new Object[capacity + 1];// 浪费一个空间,为了判断其为空或队列已满,对用户隐藏
front = tail = size = 0;
}
/**
* 循环队列元素个数
*
* @return
*/
@Override
public int getSize() {
return size;
}
/**
* 循环队列容量
*
* @return
*/
public int getCapacity() {
return data.length - 1;
}
/**
* 判断循环队列是否为空
*
* @return
*/
@Override
public boolean isEmpty() {
return front == tail;//size == 0;
}
/**
* 循环队列添加数据
*
* @param ele
*/
@Override
public void add(T ele) {
// 当front == tail时队列为空,当(tail+1)%data.length == front时队列已满
if ((tail + 1) % data.length == front) {
// 扩容
resize((data.length - 1) * 2);// 可以调用getCapacity()
}
data[tail] = ele;
size++;// 元素数量加1
tail = (tail + 1) % data.length;// 队尾指针指向下一个即将存放元素的位置
}
/**
* 扩容
*
* @param newSize
*/
private void resize(int newSize) {
T[] newDate = (T[]) new Object[newSize + 1];
for (int i = 0; i < size; i++) {
newDate[i] = data[(front + i) % data.length];
}
tail = size;// 此处可以为getSize()也可以为类属性size或者data.length-1等等
front = 0;// 更新队首指针
data = newDate;
newDate = null;
}
/**
* 循环队列队首移除元素
*
* @return
*/
@Override
public T remove() {
// 队列为空
if (front == tail) {// if(isEmpty()){
return null;
}
T result = data[front];// 存储当前队头指针所指向的元素
// 可以将当前元素置空 即 data[front] = null
front = (front + 1) % data.length;// 队头指针指向下一个元素
size--;// 循环队列元素个数减1
// 缩容
if (size == data.length / 4 && data.length / 2 > 0) {
resize(data.length / 2);
}
return result;
}
/**
* 查看队首元素
*
* @return
*/
@Override
public T getFirst() {
T result = null;
try {
result = data[front];
} catch (Exception e) {
System.out.println("error");
}
return result;
}
@Override
public String toString() {
StringBuffer sbf = new StringBuffer();
sbf.append("循环队列容量为:" + getCapacity() + ",循环队列中元素个数为:" + getSize() + ",元素为:[");
for (int i = 0; i < size; i++) {
sbf.append(data[(front + i) % data.length]);
if (i != size - 1) {
sbf.append(",");
}
}
sbf.append("]");
return sbf.toString();
}
}
main方法测试
package com.company.queue;
/**
* @Author: wenhua
* @CreateTime: 2023-01-07 12:28
*/
public class LoopTest {
public static void main(String[] args) {
LoopQueue<String> loopQueue = new LoopQueue<>(2);
System.out.println(loopQueue);// 循环队列容量为:2循环队列中元素个数为:0,元素为:[]
loopQueue.add("Jim");
System.out.println(loopQueue);// 循环队列容量为:2循环队列中元素个数为:1,元素为:[Jim]
loopQueue.add("wenhua");
System.out.println(loopQueue);// 循环队列容量为:2循环队列中元素个数为:2,元素为:[Jim,wenhua]
System.out.println("移除循环队列队首元素:"+loopQueue.remove());
System.out.println(loopQueue);
loopQueue.add("Jack");
System.out.println(loopQueue);
loopQueue.add("Jeep");
System.out.println(loopQueue);
loopQueue.add("DanNi");
System.out.println(loopQueue);
loopQueue.add("weijie");
System.out.println(loopQueue);
loopQueue.add("Deng");
System.out.println(loopQueue);
loopQueue.add("Yuan");
System.out.println(loopQueue);
loopQueue.add("Hua");
System.out.println(loopQueue);
loopQueue.add("Feng");
System.out.println(loopQueue);
while (loopQueue.getSize() != 0){
System.out.println("移除循环队列队首元素:"+loopQueue.remove());
System.out.println(loopQueue);
}
}
}
运行结果
循环队列容量为:2,循环队列中元素个数为:0,元素为:[]
循环队列容量为:2,循环队列中元素个数为:1,元素为:[Jim]
循环队列容量为:2,循环队列中元素个数为:2,元素为:[Jim,wenhua]
移除循环队列队首元素:Jim
循环队列容量为:2,循环队列中元素个数为:1,元素为:[wenhua]
循环队列容量为:2,循环队列中元素个数为:2,元素为:[wenhua,Jack]
循环队列容量为:4,循环队列中元素个数为:3,元素为:[wenhua,Jack,Jeep]
循环队列容量为:4,循环队列中元素个数为:4,元素为:[wenhua,Jack,Jeep,DanNi]
循环队列容量为:8,循环队列中元素个数为:5,元素为:[wenhua,Jack,Jeep,DanNi,weijie]
循环队列容量为:8,循环队列中元素个数为:6,元素为:[wenhua,Jack,Jeep,DanNi,weijie,Deng]
循环队列容量为:8,循环队列中元素个数为:7,元素为:[wenhua,Jack,Jeep,DanNi,weijie,Deng,Yuan]
循环队列容量为:8,循环队列中元素个数为:8,元素为:[wenhua,Jack,Jeep,DanNi,weijie,Deng,Yuan,Hua]
循环队列容量为:16,循环队列中元素个数为:9,元素为:[wenhua,Jack,Jeep,DanNi,weijie,Deng,Yuan,Hua,Feng]
移除循环队列队首元素:wenhua
循环队列容量为:16,循环队列中元素个数为:8,元素为:[Jack,Jeep,DanNi,weijie,Deng,Yuan,Hua,Feng]
移除循环队列队首元素:Jack
循环队列容量为:16,循环队列中元素个数为:7,元素为:[Jeep,DanNi,weijie,Deng,Yuan,Hua,Feng]
移除循环队列队首元素:Jeep
循环队列容量为:16,循环队列中元素个数为:6,元素为:[DanNi,weijie,Deng,Yuan,Hua,Feng]
移除循环队列队首元素:DanNi
循环队列容量为:16,循环队列中元素个数为:5,元素为:[weijie,Deng,Yuan,Hua,Feng]
移除循环队列队首元素:weijie
循环队列容量为:8,循环队列中元素个数为:4,元素为:[Deng,Yuan,Hua,Feng]
移除循环队列队首元素:Deng
循环队列容量为:8,循环队列中元素个数为:3,元素为:[Yuan,Hua,Feng]
移除循环队列队首元素:Yuan
循环队列容量为:4,循环队列中元素个数为:2,元素为:[Hua,Feng]
移除循环队列队首元素:Hua
循环队列容量为:2,循环队列中元素个数为:1,元素为:[Feng]
移除循环队列队首元素:Feng
循环队列容量为:1,循环队列中元素个数为:0,元素为:[]
以上实现底层为数组,也可以通过链表的方式,对栈,队列进行实现。