用java以数组为底层结构创建循环队列
循环队列相对于普通队列最大的变化就是添加了一个头指针head,尾指针tail。原先的普通数组队列当入队列再出队列之后,前面就会空出位置,如果要再添加元素的话只能往尾部添加,当添加到容积大小的索引时就会自动扩容往后添加,但永远都不能在前面出队的空出的位置添加,前面的位置就浪费了。循环队列很有效的解决了这一问题,通过两个指针对capacity容积取余来改变指针指向位置从而杜绝上述问题。
尾指针是入队位置的索引,每入队一个元素后,tail++。头指针是出队元素的索引,每出队一个元素后,head++。但是怎么才能循环呢?当尾指针等于capacity时,说明需要改变尾指针到开头位置来插入元素了,tail=(tail+1)%capacity。如果用这样的方法,那队满条件也得改变:(tail+1)%capacity==head。
代码如下:
looparr:底层结构:循环数组
public class LoopArr<T> { private T[] value; //保存数据 int size; //实际存放个数 int capacity; //容积 private int head; private int tail; // 构造方法 public LoopArr(int capacity){ //因为队满时要空出来一个位置,所以容积需要相较于之前的普通数组加1 if(capacity<=0){ this.capacity=11; }else { this.capacity=capacity+1; } this.size=0; this.head=this.tail=0; this.value=(T[])(new Object[this.capacity]); //不可以直接new一个T[]类型,所以需要先new一个Object[]类型然后转为T[] } //判断数组是否为空 public boolean IsEmpty(){ if(this.head==this.tail){ return true; }else{ return false; } } //向数组中添加元素 public void add(T data){ //扩容 if((this.tail+1)%this.capacity==this.head){ //如果数组满了就重新设置容积 resize((this.capacity-1)*2+1); //先把容积变为原先的容积,再×2,加1是循环队列队满时有一个空 } this.value[this.tail]=data; //因为是循环的,当队尾指到最后了就需要重新回到第一个位置继续加 this.tail=(this.tail+1)%this.capacity; this.size++; } //移除队首元素 public T remove(){ //缩容 if(this.size<=this.capacity/4&&this.capacity/2>0){ resize((this.capacity-1)/2+1); //与扩容同理 } if(IsEmpty()){ return null; }else{ T e=this.value[head]; this.value[head]=null; //head指向末尾时需要重新循环到开头,所以如下 this.head=(this.head+1)%this.capacity; this.size--; return e; } } //重新给容积 private void resize(int newcapacity){ //由于数组的容积都是不变的所以需要新建一个数组 T [] newvalue=(T[])(new Object[newcapacity]); //转移数组 for (int i = 0; i < this.size; i++) { newvalue[i]=this.value[(this.head+i)%this.capacity]; //给新数组赋值,此时capacity还没有变,所以%this.capacity } //改变容器,数组 this.value=newvalue; this.capacity=newcapacity; this.head=0; //从头开始 this.tail=this.size; //尾指针指向最后一个元素的下一个位置也就是size } public int getHead() { return head; } public int getTail() { return tail; } //获取索引位置的值 public T getindexdata(int index){ if(index<0||index>this.capacity){ throw new IllegalArgumentException("index is invalid."); } return this.value[index]; } //获取实际长度 public int getSize() { return this.size; } //获取数组的容积 public int getCapacity() { return this.capacity; } }
队列接口:用于被循环队列实现功能
public interface selfqueue<T> { //入队 void offer(T e); //出队 T poll(); //查看队首元素 T peak(); //队列中元素的个数 int getsize(); //队列是否为空 boolean IsEmpty(); }
LoopQueue:
public class LoopQueue<T> implements selfqueue<T> { private LoopArr<T> data; public LoopQueue(){ this.data=new LoopArr<T>(10); } //入队 public void offer(T e) { this.data.add(e); } //出队 public T poll() { return this.data.remove(); } //获得队首元素 public T peak() { return this.data.getindexdata(this.data.getHead()); } //获取长度 public int getsize() { return this.data.getSize(); } //获取容积 public int getcapacity(){return this.data.getCapacity();} //判断是否为空 public boolean IsEmpty() { return this.data.IsEmpty(); } }
测试:
public class queuetest<T> { public void test(LoopQueue queue, List<T> list){ //开始时间 long startTime=System.nanoTime(); //入队 System.out.println("队尾先进,入队顺序:"); for (int i = 0; i < list.size(); i++) { queue.offer(list.get(i)); System.out.print(list.get(i)+" "); } System.out.println("size:"+queue.getsize()); System.out.println("capacity:"+queue.getcapacity()); System.out.println("队列中元素个数:"+queue.getsize()); System.out.println("队头元素:"+queue.peak()); //出队 System.out.println("队头先出,出队顺序:"); while(!queue.IsEmpty()){ T e= (T) queue.poll(); System.out.print(e+" "); } //结束时间 long endTime=System.nanoTime(); System.out.println("总耗时:"+(endTime-startTime)/1000000000.0+"s"); } public static void main(String[] args) { queuetest<Integer> qt=new queuetest<Integer>(); selfqueue<Integer> queue=new LoopQueue<Integer>(); //继承了selfqueue的LoopQueue来实现selfqueue List<Integer> list=new ArrayList<Integer>(); Random r=new Random(); for (int i = 0; i < 30; i++) { list.add(r.nextInt(100)); } qt.test((LoopQueue) queue,list); } }