数据结构 - 循环队列
Posted tc971121
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 - 循环队列相关的知识,希望对你有一定的参考价值。
循环队列
在基于数组的队列中我们发现,在移出队首元素时时间复杂度为O(n),为了解决这个问题,我们引出了循环队列。
实现原理:基于数组实现,以数组头为队首,以数组尾为队尾, 此时多出一个front变量指向队首,当队首元素移出时,基于数组实现的队列中的元素不需要全部向前移动一个位置,只需要指向下一个元素。
实现循环队列的源码如下:
package queue;
public interface Queue<E> {
public void enqueue(E e);
public E dequeue();
public E getFront();
public int getSize();
public boolean isEmpty();
}
package queue;
/**
* 循环队列
*
* @author DELL
*
* @param <E>
*/
public class LoopQueue<E> implements Queue<E> {
private E[] data;
private int front; //指向队首的索引
private int tail; //指向队尾的索引
private int size; //队列中元素的个数
/**
* 构造方法
* @param capacity
* 队列的容量
*/
public LoopQueue(int capacity){
data = (E[])new Object[capacity];
front = 0;
tail = 0;
size = 0;
}
/**
* 无参构造方法,默认容量为0
*/
public LoopQueue(){
this(10);
}
/**
* 获得队列的容量
* @return
*/
public int getCapacity(){
return data.length;
}
/**
* 判断队列是否为空
*/
@Override
public boolean isEmpty() {
return size == 0;
}
/**
* 获取队列里元素的个数
*/
@Override
public int getSize() {
return size;
}
/**
* 向队列的队尾添加一个元素
*/
@Override
public void enqueue(E e) {
if (size == data.length) {
resize(data.length * 2);
}
data[tail] = e;
tail = (tail + 1) % data.length;
size++;
}
/**
* 将队首的元素移出并返回
*/
@Override
public E dequeue() {
if (isEmpty()) {
throw new IllegalArgumentException("Cannot dequeue from an emtry queue.");
}
E res = data[front];
data[front] = null;
front = (front + 1) % data.length;
size--;
if(size == data.length / 4 && data.length / 2 != 0){
resize(data.length / 2);
}
return res;
}
/**
* 瞧一眼队首的元素
*/
@Override
public E getFront() {
if (isEmpty()) {
throw new IllegalArgumentException("Queue is empty.");
}
return data[front];
}
/**
* 重置队列的容量
* @param newCapacity
*/
private void resize(int newCapacity) {
E[] newData = (E[])new Object[newCapacity];
for(int i = 0; i < size; i++){
newData[i] = data[(i + front) % data.length];
}
tail = data.length;
data = newData;
front = 0;
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append(String.format("capacity = %d size = %d
", getCapacity(),getSize()));
res.append("Front: ");
res.append(‘[‘);
int j = front; //遍历队列时记录指向队首的索引
for (int i = 0; i < size; i++) {
res.append(data[j]);
if (i != getSize() - 1) {
res.append(", ");
}
j = (j + 1) % data.length;
}
res.append(‘]‘);
res.append("tail");
return res.toString();
}
}
经典的实现循环队列实现中只用了front和tail变量,一个指向队首和一个指向队尾,size变量可以通过这两个变量推导出来,这种实现方式需要浪费一个空间,
当(front == tail时队列为空,(tail+1) % data.length == front队列满)。
循环队列的时间复杂度的分析:
*void enqueue(E e) : O(1) 均摊
*E dequeue() : O(1) 均摊
*E getFront() : O(1)
*E getSize() : O(1)
*boolean isEmpty() : O(1)
以上是关于数据结构 - 循环队列的主要内容,如果未能解决你的问题,请参考以下文章