数据结构之动态数组Queue

微笑、不失礼 提交于 2019-12-12 04:09:42

前几次我给大家分享了顺序表和栈,这次给大家分享队列。
何为队列:
在这里插入图片描述
由前几次的经验,我们书写一个Queue接口:定义如下
在这里插入图片描述

public interface Queue<E> extends Iterable<E>{
    //获取队列中元素的个数
    int getSize();
    //判断队列是否为空
    boolean isEmpty();
    //入队一个元素
    void enqueue(E e);
    //出队一个元素
    E dequeue();
    //获取队头
    E getFront();
    //获取队尾
    E getRear();
    //清空队列
    void clear();
}

我们发现,队列其实与线性表相似,只不过将顺序表的两端固定为队列的的头和尾。那么我们同样可以使用顺序表来实现队列:
在这里插入图片描述
有了前几次的经验,这次我们直接实现:

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();
    }
}

书写一个顺序队列的测试类:

/**  
* <p>Title: TestArrayQueue.java</p>  
* <p>Description: </p>  
* <p>Copyright: Copyright (c) 2017</p>  
* <p>Company: www.yaud.com</p>  
* @author XuHaobo  
* @date 2019年12月9日  
* @version 1.0  
*/

/**  
* <p>Title: TestArrayQueue</p>  
* <p>Description: </p>  
* @author XuHaobo 
* @date 2019年12月9日  
*/
public class TestArrayQueue {
	public static void main(String[] args) {
		ArrayQueue<Integer> queue =new ArrayQueue<>();
		for(int i=1;i<=15;i++) {
			queue.enqueue(i);
		}
		System.out.println(queue);
		for(int i=1;i<10;i++) {
			queue.dequeue();
		}
		System.out.println(queue);
	}
}

执行结果如下:
在这里插入图片描述
实现了顺序队列,猛然发现,顺序队列不太友好,
在这里插入图片描述
第一步优化:定义头队列的头和尾,使每次移动,头和尾直接指向头尾元素
在这里插入图片描述
在这里插入图片描述
第二步优化:那么我们考虑使其变为循环队,那么当队头/队尾移动到尾部的时候只需指向头部即可。
在这里插入图片描述
那么此时同样出现了问题:队列满和未满条件一样?我干!。
在这里插入图片描述
第三步优化:将一个空间预留出来,不存任何元素,尾指针直接指向这个null空间。
在这里插入图片描述
那么此时,队列满和判空条件不同,便解决了问题,实现了优化。
真~奥义机智。
在这里插入图片描述
接下来我们来书写循环队列:需要有头和尾,有效元素个数,以及一个空的空间。

//循环队列
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();
    }

重写迭代器,只有下一个的指向与list有所区别

@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;
        }
    }

循环队列完整代码如下:

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;
        }
    }
}

书写一个测试类用于测试:

/**  
* <p>Title: TestArrayQueueLoop</p>  
* <p>Description: </p>  
* @author XuHaobo 
* @date 2019年12月8日  
*/
public class TestArrayQueueLoop {
	 public static void main(String[] args) {
	        ArrayQueueLoop<Integer> loop=new ArrayQueueLoop<>();
	        System.out.println(loop);
	        for(int i=1;i<=15;i++){
	            loop.enqueue(i);
	        }
	        System.out.println(loop);
	        for(int i=2;i<6;i++) {
	        	loop.dequeue();
	        }
	        System.out.println(loop);
	 }
}

运行结果如下:
在这里插入图片描述
好了,今天的分享就到这里啦!!我们下次再见嗷。奥里给的嗷!!!!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!