ArrayQueue(队列)
队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表,对于队的操作也是基于线性表来进行操作,所以针对面向对象思想,我们在对队进行操作时就可以直接把队ArrayList的某些操作直接拿来用。
package DS01.动态数组;
public interface Queue<E> extends Iterable<E>{
//获取队列中元素的个数
int getSize();
//判断队列是否为空
boolean isEmpty();
//入队一个元素
void enqueue(E e);
//出队一个元素
E dequeue();
//获取队头
E getFront();
//获取队尾
E getRear();
//清空队列
void clear();
}
package DS01.动态数组;
import java.util.Iterator;
/*
* 线性队列也是基于线性表的
* */
public class ArrayQueue<E> implements Queue<E> {
private ArrayList<E> list;
public ArrayQueue(){
list=new ArrayList<>();
}
public ArrayQueue(int capacity){
list=new ArrayList<>(capacity);
}
@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();
}
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<getSize();i++){
sb.append(list.get(i));
if(i==getSize()-1){
sb.append("]");
}else {
sb.append(",");
}
}
}
return sb.toString();
}
}
ArrayQueue队列顺序存储结构的弊端
队列的顺序存储结构本身就是由ArrayList实现的
在数据元素入队的时候,相当于在ArrayList表尾添加元素
在数据元素出对的时候,相当于在ArrayList表头删除元素
很明显,入队的时间复杂度O(1),出队的时间复杂度O(n),因为出队只在表头进行,每出队一次,后面的元素就要全部向前移一位,时间复杂度较高。所以就要进行优化。
ArrayQueue的优化
第一步:让队头指针和队尾指针一样随着数据元素的变化而移动。
就是队头是动态的,每出队一个元素,队头Front就向后移动一次。出队复杂度O(1)。
第二步:第一步会使复杂度降低,但是队尾指针Rear移动到最后就不能移动了,每出队一次,表前面的空间就会空出来,会造成空间的浪费,所以可以当Front或者Rear到达尾部时,如果需要后移可重新指向表头。
第三步:第二步优化节省了空间,但是队列判空条件与队列判满条件一样,无法判断,所以我们就要始终预留一个空位置,令Rear指向空位置。
队列满的条件:(Rear+1)%n==Front
队列空的条件:Rear==Front
优化过后就变为ArrayQueueLoop
ArrayQueueLoop(循环队列)
package DS01.动态数组;
import java.util.Iterator;
//循环队列不基于顺序表,有自己独特的想法
/*
* 优化复杂度,出队时队头动态的
* 优化浪费的空间,使其变为循环的
* 预留一个空间来判满,尾指针总是指向,队尾的后一个空位
* */
/*
* 判空条件:front=rear;
* 判满条件:(rear+1)%data.length=front
*
* */
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(data.length*2);
}
data[rear]=e;
rear=(rear+1)%data.length;
size++;
}
//出队
@Override
public E dequeue() {
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
if(size<=(data.length-1)/4&&(data.length-1)/2>10){
resize(data.length/2+1);
}
E ret=data[front];
front=(front+1)%data.length;
size--;
return ret;
}
//扩容
public void resize(int newLen){
E[] newData=(E[])(new Object[newLen]);
int p=front;//重新设一个变量,从队头开始
int i=0;
while (true){
newData[i]=data[p];
p=(p+1)%data.length;//移动队头
i++;
if(p==rear){//移动完毕
break;
}
}
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];
}
//清空队列
@Override
public void clear() {
data=(E[])(new Object[11]);//多创建一个空间,有一个预留空位
front=0;
rear=0;
size=0;
}
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();
}
//仅仅只是为了遍历,支持froeach语句
@Override
public Iterator<E> iterator() {
return new ArrayQueueLoopItertor();
}
private class ArrayQueueLoopItertor implements Iterator{
int p=front;
@Override
public boolean hasNext() {//该元素是否有下一个
return p!=rear;
}
@Override
public E next() {//有直接返回下一个
E ret=data[p];
p=(p+1)%data.length;
return ret;
}
}
}