- 循环队列是对数组队列的进一步优化,
- 具体表现为 , 当移除某一元素时, 队列中的首元素索引 +1, 而不是元素集体迁移至索引零.
- 当尾元素至容器尾端时 , 会将新元素保存至队列首段的曾被移除过的索引处保存.
- 如图
- 首元素索引 : front ; 尾元素索引+1 : tail ;
- 在队列设计中 , 通过牺牲一个空间用于判断队列的空间剩余. 所以在队列初始化时, 程序内部需要多初始化一个容量
- 如何判断容器是否满 , (tail+1) % 队列容量 == front 来判断
代码如下
package sky.java.queue.xunhuanduilie;
public class LoopQueue<E> {
private E[] data;
private int front,tail;
private int size;
public LoopQueue(int capacity) {
// 浪费一个空间以用于扩容
data = (E[]) new Object[capacity+1];
front = 0;
tail = 0;
size = 0;
}
public LoopQueue() {
this(10);
}
// 容量
public int getCapacity() {
return data.length-1;
}
// 数据长度
public int size() {
return size;
}
// 是否为空
public boolean isEmpty() {
return front == tail;
}
// 入列
public void enqueue(E e) {
// 判断容器数据长度是否满-1
// 以data.length 为除数 , 取余 , 类似钟表的12点的指针,13点也可以理解为1点的同理
if ((tail+1) % data.length == front) {
resize(getCapacity() * 2);
}
data[tail] = e;
tail = (tail+1) % data.length;
size++;
}
// 扩容
private void resize(int length) {
E[] newData = (E[]) new Object[length+1];
// 循环遍历 , 复制 , 更新成员数据的值
for (int i = 0; i < size; i++) {
newData[i] = data[(front+i) % data.length];
}
front = 0;
tail=size;
data = newData;
}
// 出列
public E dequeue() {
if (isEmpty()) {
throw new RuntimeException("eee");
}
E resData = data[front];
data[front] = null;
front = (front+1) % data.length;
size--;
// 降容
if (size == getCapacity()/4 && getCapacity() != 0) {
resize(size);
}
return resData;
}
// 获取当前数据
public E front() {
if (!isEmpty()) {
return data[front];
}
return null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("front : [ ");
for (int i = front; i != tail ; i = (i+1)%data.length) {
sb.append(data[i]);
if ((i+1)%data.length != tail) {
sb.append(",");
}
}
sb.append(" ]");
return sb.toString();
}
public static void main(String[] args) {
LoopQueue<Integer> queue = new LoopQueue<>();
for (int i = 0; i < 10; i++) {
queue.enqueue(i);
System.out.println(queue);
/*if (i % 3 == 2) {
queue.dequeue();
System.out.println(queue);
}*/
}
queue.enqueue(11);
System.out.println(queue);
}
}