LeetCode 622: Design Circular Queue

Keywords: Java Programming

First, look at the data structure of queues:

Queue: FIFO data structure

In the FIFO data structure, the first element added to the queue is processed first.

As shown in the figure above, the queue is a typical FIFO data structure. The insert operation is also called enqueue, and new elements are always added at the end of the queue. The delete operation is also known as dequeue. You can only remove the first element.

Queue-implementation

To achieve queues, we can use dynamic arrays and indexes pointing to the head of the queue.

As mentioned above, queues should support two operations: queuing and queuing. Entry adds a new element to the queue and exit deletes the first element. So we need an index to point out the starting point.

Cyclic queue

Previously, we provided a simple but inefficient queue implementation.

A more effective way is to use circular queues. Specifically, we can use fixed-size arrays and two pointers to indicate the start and end positions. The goal is to reuse the wasted storage we mentioned earlier.

Let's take an example to see how circular queues work. You should pay attention to the strategies we use when entering or leaving the team.

[External Link Picture Transfer Failure (img-ScULOtla-1564547660610)(queue.gif)]

Check the animation carefully to find out the strategy we use to check whether the queue is empty or full.

The above is from China, the content has changed.

Topic: Design a circular queue:

Design your circular queue implementation. Cyclic queue is a linear data structure whose operation performance is based on FIFO (first in first out) principle and the end of the queue is connected after the head of the queue to form a cycle. It is also known as the "ring buffer".

One of the benefits of a circular queue is that we can take advantage of the space used before the queue. In a regular queue, once a queue is full, we cannot insert the next element, even if there is still room in front of the queue. But with circular queues, we can use these spaces to store new values.

Your implementation should support the following actions:

  • MyCircularQueue(k): Constructor that sets the queue length to K.
  • Front: Get elements from the head of the team. If the queue is empty, return - 1.
  • Rear: Get the tail element. If the queue is empty, return - 1.
  • enQueue(value): Insert an element into the circular queue. If successful insertion returns true.
  • deQueue(): Delete an element from the circular queue. Returns true if deleted successfully.
  • isEmpty(): Check that the circular queue is empty.
  • isFull(): Check that the circular queue is full.

Examples:

MyCircularQueue circularQueue = new MycircularQueue(3); // Set the length to 3
circularQueue.enQueue(1);  // Return true
circularQueue.enQueue(2);  // Return true
circularQueue.enQueue(3);  // Return true
circularQueue.enQueue(4);  // Return false, the queue is full
circularQueue.Rear();  // Return 3
circularQueue.isFull();  // Return true
circularQueue.deQueue();  // Return true
circularQueue.enQueue(4);  // Return true
circularQueue.Rear();  // Return 4

Tips:

  • All values are in the range of 0 to 1000.
  • Operators will be in the range of 1 to 1000.
  • Please do not use the built-in queue library.

Ideas for solving problems:

General high-level programming languages will have built-in queue libraries, a little reference can be. In a circular queue, we use an array and two pointers (head and tail). Head denotes the start of the queue and tail denotes the end of the queue.

class MyCircularQueue {
    
    private int[] data;
    private int head;
    private int tail;
    private int size;

    /** Initialize the data structure and specify the queue size k */
    public MyCircularQueue(int k) {
        data = new int[k];
        head = -1;
        tail = -1;
        size = k;
    }
    
    /** Insert an entry into the queue and return whether the insertion was successful */
    public boolean enQueue(int value) {
        if (isFull() == true) {
            return false;
        }
        if (isEmpty() == true) {
            head = 0;
        }
        tail = (tail + 1) % size;
        data[tail] = value;
        return true;
    }
    
    /** Delete an item from the queue and return whether the deletion was successful */
    public boolean deQueue() {
        if (isEmpty() == true) {
            return false;
        }
        if (head == tail) {
            head = -1;
            tail = -1;
            return true;
        }
        head = (head + 1) % size;
        return true;
    }
    
    /** Get the first item of the queue */
    public int Front() {
        if (isEmpty() == true) {
            return -1;
        }
        return data[head];
    }
    
    /** Get the last item of the queue */
    public int Rear() {
        if (isEmpty() == true) {
            return -1;
        }
        return data[tail];
    }
    
    /** Check if the queue is empty */
    public boolean isEmpty() {
        return head == -1;
    }
    
    /** Check if the queue is full */
    public boolean isFull() {
        return ((tail + 1) % size) == head;
    }
}

Python3:

class MyCircularQueue():

    def __init__(self, k: int):
        """
        //Initialize the data structure and specify the queue size k
        """
        self.size = k
        self.queue = ['']*k
        self.head = -1
        self.tail = -1
        
    def enQueue(self, value: int) -> bool:
        """
        //Insert an entry into the queue and return whether the insertion was successful
        """
        if not self.isFull():
            if self.head == -1:
                self.head = 0
            self.tail = (self.tail+1)%self.size
            self.queue[self.tail] = value
            return True
        else:
            return False
        
    def deQueue(self) -> bool:
        """
        //Delete an item from the queue and return whether the deletion was successful
        """
        if not self.isEmpty():
            if self.head ==self.tail:
                self.head,self.tail = -1,-1
            else:
                self.head = (self.head+1)%self.size
            return True
        else:
            return False

    def Front(self) -> int:
        """
        //Get the first item of the queue
        """
        if self.isEmpty():
            return -1
        else:
            return self.queue[self.head]

    def Rear(self) -> int:
        """
        //Get the last item of the queue
        """
        if self.isEmpty():
            return -1
        else:
            return self.queue[self.tail]

    def isEmpty(self) -> bool:
        """
        //Check if the queue is empty
        """
        return self.head == -1 and self.tail == -1

    def isFull(self) -> bool:
        """
        //Check if the queue is full
        """
        return (self.tail+1)%self.size ==self.head

Posted by dannyb785 on Wed, 31 Jul 2019 04:58:53 -0700