Cycle was deque

Circular queue is a linear data structure, based on the operation performance FIFO(FIFO) principle and is connected to the tail after the head of the queue to form a loop. It is also called a ring buffer .

One of the benefits circular queue is used before we can use this queue space. In a normal queue, once a queue is full, we can not insert the next element, even if there is still space in the front of the queue. However, the use of circular queue, we can use the space to store the new value.

Why use a circular queue?

Here we first cohort simple implementation of a simple display, queue should support two modes of operation: into the team and the team .

class MyQueue {
    // store elements
    private List<Integer> data;         
    // a pointer to indicate the start position
    private int p_start;            
    public MyQueue() {
        data = new ArrayList<Integer>();
        p_start = 0;
    }
    /** Insert an element into the queue. Return true if the operation is successful. */
    public boolean enQueue(int x) {
        data.add(x);
        return true;
    };    
    /** Delete an element from the queue. Return true if the operation is successful. */
    public boolean deQueue() {
        if (isEmpty() == true) {
            return false;
        }
        p_start++;
        return true;
    }
    /** Get the front item from the queue. */
    public int Front() {
        return data.get(p_start);
    }
    /** Checks whether the queue is empty or not. */
    public boolean isEmpty() {
        return p_start >= data.size();
    }     
}

Shortcoming

The above realization is very simple, but in some cases inefficient. With the movement of the starting pointer, wasting more and more space. When we have space constraints, it would be difficult to accept.

Let us consider a situation in which we can only allocate a maximum length of the array 5. When we add only less than 5 elements, our solution is effective. For example, if we only want to call into the team you want to function four elements 10 into the team, then we can be successful.

But we can not accept any more requests into the team, which is reasonable, because the queue is full. But if we put a team out of the elements of it?

In fact, in this case, we should be able to accept an element.

Circular queue demand is imminent.

Design ideas

Here are direct copies of liweiwei1419 wonderful explanations :

1, the loop variable is defined front and rear. This definition has remained, in the end is to move the pointer or the first assignment is very easy to think clearly.

front:指向队列头部第 1 个有效数据的位置;
rear:指向队列尾部(即最后 1 个有效数据)的下一个位置,即下一个从队尾入队元素的位置。

(说明:这个定义是依据“动态数组”的定义模仿而来。)

2、为了避免“队列为空”和“队列为满”的判别条件冲突,我们有意浪费了一个位置。

浪费一个位置是指:循环数组中任何时刻一定至少有一个位置不存放有效元素。

判别队列为空的条件是:front == rear;

判别队列为满的条件是:(rear + 1) % capacity == front;。可以这样理解,当 rear 循环到数组的前面,要从后面追上 front,还差一格的时候,判定队列为满。

3、因为有循环的出现,要特别注意处理数组下标可能越界的情况。指针后移的时候,索引 + 1,并且要注意取模。

例题

本文的写作目的就是为了 再次手写一边算法练手

622.设计循环队列

  • 难度:Medium

参考上述设计思路,很容易编写代码,需要注意的是取模代码的编写相对容易出问题。

实现代码:

class MyCircularQueue {

    private int front;
    private int tail;
    private int capacity;
    private int[] arr;

    public MyCircularQueue(int k) {
        this.capacity = k + 1;
        this.arr = new int[capacity];

        this.front = 0;
        this.tail = 0;
    }

    public boolean enQueue(int value) {
        if (isFull()) return false;

        arr[tail] = value;
        tail = (tail + 1) % capacity;
        return true;
    }

    public boolean deQueue() {
        if (isEmpty()) return false;

        front = (front + 1) % capacity;
        return true;
    }

    public int Front() {
        if (isEmpty()) return -1;
        return arr[front];
    }

    public int Rear() {
        if (isEmpty()) return -1;
        return arr[(tail - 1 + capacity) % capacity];
    }

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

    public boolean isFull() {
        return (tail + 1) % capacity == front;
    }
}

641. 设计循环双端队列

  • 难度:Medium

和上题基本相似,除了多几个取模运算,几乎没什么变化。

class MyCircularDeque {

    private int front;
    private int tail;
    private int capacity;
    private int[] arr;

    public MyCircularDeque(int k) {
        this.capacity = k + 1;
        this.arr = new int[capacity];

        this.front = 0;
        this.tail = 0;
    }

    public boolean insertFront(int value) {
        if (isFull()) return false;

        front = (front - 1 + capacity) % capacity;
        arr[front] = value;
        return true;
    }

    public boolean insertLast(int value) {
        if (isFull()) return false;

        arr[tail] = value;
        tail = (tail + 1) % capacity;
        return true;
    }

    public boolean deleteFront() {
        if (isEmpty()) return false;

        front = (front + 1) % capacity;
        return true;
    }

    public boolean deleteLast() {
        if (isEmpty()) return false;

        tail = (tail - 1 + capacity) % capacity;
        return true;
    }

    public int getFront() {
        if (isEmpty()) return -1;
        return arr[front];
    }

    public int getRear() {
        if (isEmpty()) return -1;
        return arr[(tail - 1 + capacity) % capacity];
    }

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

    public boolean isFull() {
        return (tail + 1) % capacity == front;
    }
}

参考 & 感谢

文章绝大部分内容节选自LeetCode

https://leetcode-cn.com/problems/design-circular-queue

https://leetcode-cn.com/problems/design-circular-deque

感谢 liweiwei1419 提供的精彩的 题解

关于我

Hello,我是 却把清梅嗅 ,如果您觉得文章对您有价值,欢迎 ❤️,也欢迎关注我的 博客 或者 GitHub

如果您觉得文章还差了那么点东西,也请通过关注督促我写出更好的文章——万一哪天我进步了呢?

发布了99 篇原创文章 · 获赞 396 · 访问量 47万+

Guess you like

Origin blog.csdn.net/mq2553299/article/details/104057271