数据结构入门——大师:queue(二) LoopQueue

1.什么是循环队列

由于队列会出队入队,因此我们需要利用好队列出队的空间,因此我们需要设置循环队列

2.循环队列的实现

循环队列和之前简单队列不同,因此我们需要从头开始实现

 /**
     * 定义队首和队尾
     */
    private int front,tail;
     //底层还是数组
    private E[] data;
    private int size;

  • 循环队列有个队首和队尾,队首指向队列的头,队尾指向队列尾部,队尾到数组的最后时候,再入队,会指向数组头部
  • 循环队列需要浪费一个空间:由于入队时尾指针向前追赶头指针;出队时头指针向前追赶尾指针,造成队空和队满时头尾指针均相等。因此,无法通过条件front==tail来判别队列是"空"还是"满"。

解决这个问题的方法至少有三种:

① 另设一[布尔变量]以区别队列的空和满;

② 少用一个元素的空间。约定入队前,测试尾指针在循环意义下加1后是否等于头指针,若相等则认为队满
(注意:tail所指的单元始终为空);

③使用一个计数器记录队列中元素的总数(即队列长度)。

2.循环队列的初始化操作


    public LoopQueue(int capacity){
        //循环队列需要浪费一个空间
        data = (E[]) new Object[capacity + 1];
        front = 0;
        tail = 0;
        size = 0;
    }

    public int getCapacity(){
        return data.length - 1;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return front == tail;
    }
}

3.入队

  @Override
    public void enqueue(E e) {
        //判断队满
        // ,那么 tail+1=front才能代表队满,为了使得两个不能超过data.length所以需要%一下
        if((tail + 1) % data.length == front ){
            //需要扩容
            resize(getCapacity() * 2);
        }
        //数据放到队尾
        data[tail] = e;
        //本来是tail = tail +1即可,因为到数组长度的最大值需要重头再来,所以需要% 重新开始计
        tail = (tail + 1)%data.length;
        size ++;
    }
}

入队就是如果tail + 1=front 进行扩容,如果不是那么就将元素放在tail位置,然后tail+1指向后一个空的地方

4.队列扩容

 private void resize(int newCapacity){
        E[] newData =(E[]) new Object[newCapacity + 1];
        //本质上%data.length 反正数组越界,因为这个值肯定是小于data.length的,
        // 当其 大于等于6时候会从0重新计数,而循环队列原数组的数据也是这样的
        for(int i = 0; i < size; i ++){
            newData[i] = data[(i + front) % data.length];
        }
        data = newData;
        tail = size;
        front = 0;
    }
}

扩容的结果就是原来队列的头是新数组的头部,原来队列尾在旧的数组

5.出队

 @Override
    public E dequeue() {
        if(isEmpty()){
            throw new IllegalArgumentException("queue is empty");
        }
        E ret = data[front];
        data[front] = null;
        front =( front + 1) % data.length;
        size --;
        //出队,那就要缩容
        if(size == getCapacity() / 2 && getCapacity() / 2 != 0){
            resize(getCapacity() / 2);
        }
        return ret;
    }

    @Override
    public E getFront() {
        if(isEmpty()){
            throw new IllegalArgumentException("queue is empty");
        }
        return data[front];
    }

出队就是将front元素抛出去,然后置空,front后移一位,然后进行缩容,本质上属于饿汉式缩容,因为size一减少就会去缩容

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 11,342评论 0 13
  • 栈与列队 栈是限定仅在表尾进行插入和删除操作的线性表 队列是只允许在一端进行插入操作、而在另一端进行删除操作的线性...
    Longshihua阅读 4,832评论 0 3
  • 第三章 栈和队列 栈和队列的定义和特点 1、栈的定义和特点 栈(Stack)是限制在表的一端进行插入和删除运算的线...
    游戏原画设计阅读 7,096评论 0 1
  • 前言: 数据结构是计算机相关专业的基础课程,不管学什么编程语言,都要学习数据结构。接下来就一起来了解一下吧。 欢迎...
    贪挽懒月阅读 3,982评论 2 17
  • 现在的毛病就是眼高手低,总想干点大事,干点有意义的事情,一般的小事都觉得没啥意义。 就拿小区门口的小店老板来说吧,...
    库因塔阅读 767评论 0 0