队列

作者: Leo_up_up | 来源:发表于2020-04-19 21:36 被阅读0次

       队列,是一个先进先出的数据结构,与栈一样,队列也是一种数组与链表的一种的受限操作所形成的特殊数据结构。

    相比于栈的先进后出,队列的先进先出是怎么样一个抽象模型呢。

    队列模型

    队列只支持两个操作,分别是入队和出队,入队只能在队尾进行,出队只能在队头进行。

    队列作为一种基础的数据结构,它的应用是十分广泛的。其中以它的一些特殊实现为最,比如循环队列,阻塞队列,并发队列,优先队列等。

    下面以数组来实现一个简单的队列。

    /**

    * 以数组实现队列

    */

    public class Queue_4_19 {

    private static int DEFAULT_SIZE =10;

    private int tail =0;// 队尾

        private int font =0;// 队头

        private int[]array;

    public Queue_4_19() {

    this(DEFAULT_SIZE);

    }

    public Queue_4_19(int size) {

    array =new int[size];

    }

    private boolean enqueue(int val) {

    if (tail ==array.length -1) {// 判满

                return false;

    }

    array[tail++] = val;

    return true;

    }

    private boolean dequeue() {

    if (font ==tail) {// 判空

                return false;

    }

    font++;

    return true;

    }

    }

    从上面的代码可以看出来,当tail==n时,这个队列就无法插入新元素了,那么当里面的元素全部出队时,这个队列就不可用了,那么我们就可以设计一个循环队列来解决这种问题。

    与普通队列不同的是,循环队列可以理解为一个圆形环。下面放上两张图,可以更好的理解。

    循环队列A 循环队列B

    从上图的循环队列A可以看出,此时的队尾已经指向了数组的最后一个下标,按照普通的队列,这个时候已经无法插入了,但是我们可以看到,此时数组下标0-3都是没有元素,表明可以插入的,那我们可以怎么做呢,这个时候,我们把数据a放进数组,但是我们不把tail更新为8,而是更新为0,然后继续放入b,把tail更新为1。然后就变成了循环队列B这个样子。

    这就是循环队列的设计理念,与普通队列一样,循环队列的关键也在于判空与判满,就像循环队列A哪个图,如果依然按照tail==array.length -1来判满,那么就无法插入新的数据,这是不对的。但是判空与普通队列一样,依然是font==tail。

    下面上一张图,可以更好理解怎么判满:

    循环队列判满

    计算下标,多画一些图,就可以得到规律,当(tail+1)%(array.length)==font时,就标明队列已经满了,我们这个样子设计,会浪费一个存储单元,为什么要这个样子,因为如果tail==font,那么就和判空冲突了,当然,这个也可以解决,使用一个计数器就可以,不过相比于在维护一个计数器,单纯浪费一个存储单元更可以接受,也更简单。下面写出循环队列的实现代码:

    /**

    * Insert an element into the circular queue. Return true if the operation is successful.

    */

    public boolean enQueue(AnyType value) {//需要判断满

        if (isFull())

    return false;

    array[tail] = value;

    tail = (tail +1) %array.length;

    return true;

    }

    /**

    * Delete an element from the circular queue. Return true if the operation is successful.

    */

    public boolean deQueue() {

    if(isEmpty())

    return false;

    font = (font+1)%array.length;

    return true;

    }

    /**

    * Checks whether the circular queue is empty or not.

    */

    public boolean isEmpty() {

    return font ==tail;//头指针尾指针指向同一位置

    }

    /**

    * Checks whether the circular queue is full or not.

    */

    public boolean isFull() {

    return (tail +1) %array.length ==font;

    }

    这就是循环队列的实现。相比于单纯的队列,更加应用广泛。

    阻塞队列

    相比于上面的普通队列,循环队列,阻塞队列的应用场景更加广泛,组织队列的含义就是,当队列空的时候,我们就阻止从队头取数据,当队列满的时候,我们就阻止从队尾放数据。

    阻塞队列A 阻塞队列B

    基于这样一个概念,我们可以轻松的设计出一个生产者--消费者模型,可以有效协调生产者和消费者的效率,当生产者生产过多二消费不了时,队列就会满,此时就停止生产,而当消费过多生产不够时,就阻止消费操作。同时,我们也可以配置多个消费者同时消费,当生产过多时,这样可以更好的利用资源。

    上面就是队列的一些概念与实现。也可以做一些专门题目进行训练。

    相关文章

      网友评论

          本文标题:队列

          本文链接:https://www.haomeiwen.com/subject/agribhtx.html