队列Queue:(对比栈学习)
线性结构
只能从一端添加元素,从另外一端取出元素(先进先出-FIFO)
时间复杂度O(1)
出队时间复杂度O(n)
public class ArrayQueue<E> implements Queue<E> {
private Array<E> array;
public ArrayQueue(int capacity) {
array = new Array<>(capacity);
}
public ArrayQueue() {
array = new Array<>();
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
public int getCapacity() {
return array.getCapacity();
}
@Override
public void enqueue(E e) {// 放出的时候从队列的尾放入
array.addLast(e);
}
@Override
public E dequeue() {// 取出的时候从队列的头取出
return array.removeFirst();
}
@Override
public E getFront() {
return array.getFirst();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Queue:");
sb.append("front[");
for (int i = 0; i < array.getSize(); i++) {
sb.append(array.get(i));
if (i != array.getSize() - 1)
sb.append(", ");
}
sb.append("] tail");
return sb.toString();
}
public static void main(String[] args) {
ArrayQueue<Integer> queue = new ArrayQueue<>();
for (int i = 0; i < 10; i++) {
queue.enqueue(i);
System.out.println(queue);
if (i % 3 == 2)
queue.dequeue();
System.out.println(queue);
}
}
}
循环队列
弥补出队复杂度O(n),现在的时间复杂度是O(1);
实现循环队列
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];//有意的浪费一个空间
size = 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 = (tail+1)%data.length;
size++;
}
}
private void resize(int newCapacity) {//扩容
E[] newData = (E[])new Object[newCapacity+1];
for(int i = 0;i<size;i++) {
newData[i] = data[(front+i)%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];
data[front] = null;
front = (front+1)%data.length;
size--;
//避免开辟太多的空间
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!=size; 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<>();
for (int i = 0; i < 10; i++) {
queue.enqueue(i);
System.out.println(queue);
if (i % 3 == 2)
queue.dequeue();//每隔三个数 出队
System.out.println(queue);
}
}
}
循环队列与队列的差别
对于Array Queue来说每执行一次出队操作,所有的元素都要移一次,时间复杂度是O(n);
对于LoopQueue来说出队入队时间复杂度都是O(1);
public class Main {
public static void main(String []args) {
int opCount = 10000;
ArrayQueue<Integer> arrayQueue = new ArrayQueue<>();
double time1 = testQueue(arrayQueue,opCount);
System.out.println("ArrayQueue,time:"+time1+"s");
LoopQueue<Integer> LoopQueue = new LoopQueue<>();
double time2 = testQueue(arrayQueue,opCount);
System.out.println("LoopQueue,time:"+time2+"s");
}
private static double testQueue(Queue<Integer>q,int opCount) {
long startTime = System.nanoTime();
Random r = new Random();
for(int i = 0;i<opCount;i++) {
q.enqueue(r.nextInt(Integer.MAX_VALUE));//入队最大值
}
for(int i = 0;i<opCount;i++) {
q.dequeue();
}
long endTime = System.nanoTime();
return (endTime-startTime)/100000000.0;
}
}
队列的应用:
使用计算机来模拟生活中队列,都可使用队列。
组件计算机的其他算法,广度优先遍历