多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] # 数组队列的问题 数组队列的出队复杂度是O(n) 队列的首移除,不把里面的元素重新排列,就把font指向向后移动 **font == tail 队列为空** **(tail+1)%c == front 队列满** ![](https://box.kancloud.cn/1d78848ea4e5959824a58e6c1d5462c9_1070x414.png) 如果tail到最后,这个数组此时不应该扩容,因为数组前面有空间没有被利用 ![](https://box.kancloud.cn/9ad605db9e283ab8a066e20f8ccc7b8c_1074x405.png) 那么这时候应该把tail移动到前面没有用的位置 ![](https://box.kancloud.cn/b41641d4ff85d8af096977dbadf14149_1061x411.png) capacity中,浪费一个空间 # 接口 还是用之前的动态数组 ~~~ public interface Queue<E> { int getSize(); boolean isEmpty(); void enqueue(E e); E dequeue(); E getFront(); } ~~~ # 实现类 ~~~ public class LoopQueue<E> implements Queue<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; } @Override public int getSize() { return size; } @Override public boolean isEmpty() { return front == tail; } //入队 @Override public void enqueue(E e) { if ((tail + 1) % data.length == front) { //表示要扩容 resize(getCapacity() * 2); } data[tail] = e; //添加了一个元素,tail就要+1,同时为了防止数组满了,需要跑队列前面 tail = (tail + 1) % data.length; size++; } //扩容 private void resize(int newCapacity) { //在构造函数那边还会再+1的 E[] newData = (E[]) new Object[newCapacity + 1]; for (int i = 0; i < size; i++) { //位置可能会跑到前面,但是数组不能越界,最终这个位置会被放到后面 //就像被重新拉长了 newData[i] = data[(i + front) % data.length]; } data = newData; front = 0; //对尾就是这个最大长度 tail = size; } //出队 @Override public E dequeue() { //空队列是不能出队的 if (isEmpty()) { throw new IllegalArgumentException("Cannot dequeue from an empty queue."); } //出队是要把头部的元素出去 E ret = data[front]; //把头部元素的引用置为null,让他可以被gc,占着引用无法gc data[front] = null; //头元素向后移动1位,同时不能超过数组的长度 front = (front + 1) % data.length; size--; //如果出队之后,装的元素少于1/4就缩容,但是队列中元素不能为0 if (size == getCapacity() / 4 && getCapacity() / 2 != 0) { //进行缩容 resize(getCapacity() / 2); } return ret; } //获取对首 @Override public E getFront() { //空队列是不能出队的 if (isEmpty()) { throw new IllegalArgumentException("Queue is empty"); } return data[front]; } @Override public String toString() { StringBuilder res = new StringBuilder(); res.append(String.format("Queue: size=%d,capacity=%d\n", size, getCapacity())); res.append("front ["); //由于是循环队列 for (int i = front; i != tail; i = (i + 1) % data.length) { res.append(data[i]); //如果不是最后一个元素 if (i+1 % data.length != tail) { res.append(", "); } } res.append("] tail"); return res.toString(); } } ~~~ # 测试 ~~~ public static void main(String[] args) { LoopQueue<Integer> queue = new LoopQueue<Integer>(); for (int i = 0; i<10; i++) { queue.enqueue(i); System.out.println(queue); if (i % 3 ==2) { queue.dequeue(); System.out.println(queue); } } } ~~~ # 复杂度分析 ![](https://box.kancloud.cn/ef25c933e2657284e0b2855080260be5_796x562.png)