一、队列的顺序存储结构
1)队列的定义
- 队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表
- 队列是一种先进先出(First In Last Out)的线性表,简称FIFO
- 允许插入的一端称为队尾,允许删除的一端称为队头
2)队列接口Queue的定义
public interface Queue<E> extends Iterable<E>{
//获取队列中元素的个数
int getSize();
//判断队列是否为空
boolean isEmpty();
//入队一个元素
void enqueue(E e);
//出队一个元素
E dequeue();
//获取队头
E getFront();
//获取队尾
E getRear();
//清空队列
void clear();
}
3)队列的顺序存储结构ArrayQueue的定义
import java.util.Iterator;
public class ArrayQueue<E> implements Queue<E> {
private ArrayList<E> list;
public ArrayQueue(){
list=new ArrayList<>();
}
@Override
public int getSize() {
return list.getSize();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public void enqueue(E e) {
list.addLast(e);
}
@Override
public E dequeue() {
return list.removeFirst();
}
@Override
public E getFront() {
return list.getFirst();
}
@Override
public E getRear() {
return list.getLast();
}
@Override
public void clear() {
list.clear();
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append(String.format("ArrayQueue: %d/%d\n",getSize(),list.getCapacity()));
sb.append('[');
if(isEmpty()){
sb.append(']');
}else{
for(int i=0;i<list.getSize();i++){
sb.append(list.get(i));
if(i==list.getSize()-1){
sb.append(']');
}else{
sb.append(',');
}
}
}
return sb.toString();
}
}
二、队列的顺序存储结构
1)队列顺序存储结构的弊端
- 队列的顺序存储结构本身是由ArrayList实现的
- 在数据元素入队的时候,相当于在ArrayList表尾添加元素
- 在数据元素出队的时候,相当于在ArrayList表头删除元素
- 很明显,入队的时间复杂度O(1),出队的时间复杂度O(n)
- 线性表增删数据元素时间复杂符都是O(n),但是这个是按平均算的
- 队列的出队时间复杂度O(n),可不是按平均算的,因为每次出队都是O(n)
2)优化第1步
能否让队头指针和队尾指针一样随着数据元素的变化而移动?
这样子入队和出队操作都是O(1)
但是,问题也很明显
- Rear指针不能再继续后移了
- 浪费了一些空间
3)优化第2步
当队尾或队头指针到达尾部时,如需后移可重新指向表头
这样子解决了浪费空间的问题
但是,如何判断队列已满?如何判断队列为空?
经过计算我们发现两个判断条件一模一样
队列满的条件 (Rear+1)%n==Front
队列空的条件 (Rear+1)%n==Front
这样肯定是不行的
3)优化第3步
我们将一个空间预留出来不存任何元素,尾指针始终指向这个null空间
队列满的条件 (Rear+1)%n==Front
队列空的条件 Rear==Front
import java.util.Iterator;
//循环队列
public class ArrayQueueLoop<E> implements Queue<E> {
private E[] data;
private int front;
private int rear;
private int size;
public ArrayQueueLoop(){
data= (E[]) (new Object[11]);//因为有一个空的空间
front=0;
rear=0;
size=0;
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size==0&&front==rear;
}
@Override
public void enqueue(E e) {
if((rear+1)%data.length==front){
resize(2*data.length-1);
}
data[rear]=e;
rear=(rear+1)%data.length;
size++;
}
@Override
public E dequeue() {
if(isEmpty()){
throw new IllegalArgumentException("队列空");
}
E ret=data[front];
front=(front+1)%data.length;
size--;
if(size<=(data.length-1)/4&&(data.length-1)/2>=10){
resize((data.length-1)/2+1);
}
return ret;
}
private void resize(int newLen){
E[] newData= (E[]) (new Object[newLen]);
int p=front;
int i=0;
while(true){
newData[i]=data[p];
i++;
p=(p+1)%data.length;
if(p==rear){
break;
}
}
front=0;
rear=size;
data=newData;
}
@Override
public E getFront() {
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
return data[front];
}
@Override
public E getRear() {
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
return data[(rear-1+data.length)%data.length];
}
@Override
public void clear() {
data= (E[]) (new Object[11]);//因为有一个空的空间
front=0;
rear=0;
size=0;
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append(String.format("ArrayQueueLoop: %d/%d\n",size,data.length-1));
sb.append('[');
if(isEmpty()){
sb.append(']');
}else{
for(int i=front;i!=rear;i=(i+1)%data.length){
sb.append(data[i]);
if((i+1)%data.length==rear){
sb.append(']');
}else{
sb.append(',');
}
}
}
return sb.toString();
}
@Override
public Iterator<E> iterator() {
return new ArrayQueueLoopIterator();
}
private class ArrayQueueLoopIterator implements Iterator{
int p=front;
@Override
public boolean hasNext() {
return p!=rear;
}
@Override
public Object next() {
E ret=data[p];
p=(p+1)%data.length;
return ret;
}
}
}