Open In App

Design a Queue data structure to get minimum or maximum in O(1) time

Improve
Improve
Like Article
Like
Save
Share
Report

Problem: Design a Data Structure a SpecialQueue which supports following operations enqueue, deque, getMin() or getMax() where getMin() operation takes O(1) time.
Example: 
 

Let the data to be inserted in queue be -
4, 2, 1, 6

Operation Queue Output
push(4) 4 -
push(2) 4, 2 -
push(1) 4, 2, 1 -
getMin() 4, 2, 1 1
push(6) 4, 2, 1, 6 -
pop() 2, 1, 6 4
pop() 1, 6 2
pop() 6 1
getMin() 6 6

// Notice the getMin() function call
// It returns the minimum element
// of all the values present in the queue

 

Approach: The idea is to use Doubly ended Queue to store in increasing order if the structure is to return the minimum element and store in decreasing order if the structure is to return the maximum element. The operations of the Data Structure is defined as follows:
 

Enqueue

  • Insert the element into the queue structure.
  • If the size of the Deque structure is empty that is the size of the Deque is 0. Then, Insert the element from the back.
  • Otherwise, If there are some elements in the Deque structure then pop the elements out from the Deque until the back of the Deque is greater than the current element and then finally insert the element from back.

 

Deque

  • If the first element of the Deque is equal to the front element of the queue then pop the elements out from the Queue and the Deque at the same time.
  • Otherwise, Pop the element from the front of the queue to maintain the order of the elements.

 

Get Minimum

Return the front element of the Deque to get the minimum element of the current element of the queue.
Below is the implementation of the above approach:
 

C++




// C++ implementation to design
// a queue data structure to get
// minimum element in O(1) time
 
#include <bits/stdc++.h>
 
using namespace std;
 
template <typename T>
 
// Structure of the queue
class MinMaxQueue {
public:
    // Queue to store the
    // element to maintain the
    // order of insertion
    queue<T> Q;
 
    // Doubly ended queue to
    // get the minimum element
    // in the O(1) time
    deque<T> D;
 
    // Function to push a element
    // into the queue
    void enque_element(T element)
    {
        // If there is no element
        // in the queue
        if (Q.size() == 0) {
            Q.push(element);
            D.push_back(element);
        }
        else {
            Q.push(element);
 
            // Pop the elements out
            // until the element at
            // back is greater than
            // current element
            while (!D.empty() && D.back() > element) {
                D.pop_back();
            }
            D.push_back(element);
        }
    }
 
    // Function to pop the element
    // out from the queue
    void deque_element()
    {
        // Condition when the Minimum
        // element is the element at
        // the front of the Deque
        if (Q.front() == D.front()) {
            Q.pop();
            D.pop_front();
        }
        else {
            Q.pop();
        }
    }
 
    // Function to get the
    // minimum element from
    // the queue
    T getMin() { return D.front(); }
};
 
// Driver Code
int main()
{
    MinMaxQueue<int> k;
    int example[3] = { 1, 2, 4 };
 
    // Loop to enque element
    for (int i = 0; i < 3; i++) {
        k.enque_element(example[i]);
    }
    cout << k.getMin() << "\n";
    k.deque_element();
    cout << k.getMin() << "\n";
}


Java




import java.io.*;
import java.util.*;
 
class SpecialQueue {
 
    Queue<Integer> q;
    Deque<Integer> dq;
 
    public SpecialQueue()
    {
        q = new LinkedList<>();
        dq = new ArrayDeque<>();
    }
 
    void enque(int data)
    {
        // remove all elements from
        // from deque which are greater
        // than the current element 'data'
        while (!dq.isEmpty() && dq.getLast() > data) {
            dq.removeLast();
        }
        // If queue is empty then
        // while loop is skipped.
        dq.addLast(data);
        q.add(data);
    }
 
    void deque()
    {
        // If min element is present
        // at front of queue
        if (dq.getFirst() == q.peek()) {
            dq.removeFirst();
        }
        q.remove();
    }
 
    // Method to get min element in Queue
    int getMin() throws Exception
    {
        // If queue is Empty, return Exception
        if (q.isEmpty())
            throw new Exception("Queue is Empty");
        else
            return dq.getFirst();
    }
    public static void main(String[] args) throws Exception
    {
        SpecialQueue arr = new SpecialQueue();
        arr.enque(1);
        arr.enque(2);
        arr.enque(4);
        System.out.println(arr.getMin());
        arr.deque();
        System.out.println(arr.getMin());
    }
}


Python3




# Python 3 implementation to design
# a queue data structure to get
# minimum element in O(1) time
from collections import deque as dq
 
# class for the queue
 
 
class MinMaxQueue:
 
    def __init__(self):
        # Queue to store the
        # element to maintain the
        # order of insertion
        self.Q = dq([])
 
        # Doubly ended queue to
        # get the minimum element
        # in the O(1) time
        self.D = dq([])
 
    # Function to push a element
    # into the queue
    def enque_element(self, element):
        # If there is no element
        # in the queue
        if (len(self.Q) == 0):
            self.Q.append(element)
            self.D.append(element)
 
        else:
            self.Q.append(element)
 
            # Pop the elements out
            # until the element at
            # back is greater than
            # current element
            while (self.D and
                   self.D[-1] > element):
                self.D.pop()
 
            self.D.append(element)
 
    # Function to pop the element
    # out from the queue
 
    def deque_element(self,):
        # Condition when the Minimum
        # element is the element at
        # the front of the Deque
        if (self.Q[0] == self.D[0]):
            self.Q.popleft()
            self.D.popleft()
 
        else:
            self.Q.popleft()
 
    # Function to get the
    # minimum element from
    # the queue
 
    def getMin(self,):
        return self.D[0]
 
 
# Driver Code
if __name__ == '__main__':
    k = MinMaxQueue()
    example = [1, 2, 4]
 
    # Loop to enque element
    for i in range(3):
        k.enque_element(example[i])
 
    print(k.getMin())
    k.deque_element()
    print(k.getMin())


C#




using System;
using System.Collections.Generic;
 
class SpecialQueue {
    Queue<int> q;
    List<int> dq;
 
    public SpecialQueue()
    {
        q = new Queue<int>();
        dq = new List<int>();
    }
 
    void Enque(int data)
    {
        // remove all elements from
        // from deque which are greater
        // than the current element 'data'
        while (dq.Count > 0 && dq[dq.Count - 1] > data) {
            dq.RemoveAt(dq.Count - 1);
        }
        // If queue is empty then
        // while loop is skipped.
        dq.Add(data);
        q.Enqueue(data);
    }
 
    void Deque()
    {
        // If min element is present
        // at front of queue
        if (dq[0] == q.Peek()) {
            dq.RemoveAt(0);
        }
        q.Dequeue();
    }
 
    // Method to get min element in Queue
    int GetMin()
    {
        // If queue is Empty, return Exception
        if (q.Count == 0) {
            throw new Exception("Queue is Empty");
        }
        else {
            return dq[0];
        }
    }
 
    public static void Main(string[] args)
    {
        SpecialQueue arr = new SpecialQueue();
        arr.Enque(1);
        arr.Enque(2);
        arr.Enque(4);
        Console.WriteLine(arr.GetMin());
        arr.Deque();
        Console.WriteLine(arr.GetMin());
    }
}
 
// This code is contributed by phasing17


Javascript




class MinMaxQueue {
  constructor() {
    // Queue to store the element to maintain the order of insertion
    this.Q = [];
 
    // Doubly ended queue to get the minimum element in the O(1) time
    this.D = [];
  }
 
  // Function to push a element into the queue
  enqueElement(element) {
    // If there is no element in the queue
    if (this.Q.length === 0) {
      this.Q.push(element);
      this.D.push(element);
    } else {
      this.Q.push(element);
 
      // Pop the elements out until the element at back is greater than current element
      while (this.D.length > 0 && this.D[this.D.length - 1] > element) {
        this.D.pop();
      }
 
      this.D.push(element);
    }
  }
 
  // Function to pop the element out from the queue
  dequeElement() {
    // Condition when the Minimum element is the element at the front of the Deque
    if (this.Q[0] === this.D[0]) {
      this.Q.shift();
      this.D.shift();
    } else {
      this.Q.shift();
    }
  }
 
  // Function to get the minimum element from the queue
  getMin() {
    return this.D[0];
  }
}
 
// Driver Code
function main() {
  const k = new MinMaxQueue();
  const example = [1, 2, 4];
 
  // Loop to enque element
  for (let i = 0; i < 3; i++) {
    k.enqueElement(example[i]);
  }
 
  console.log(k.getMin());
  k.dequeElement();
  console.log(k.getMin());
}
 
main();
 
// This code is contributed by phasing17


Output

1
2

Time and Space of Complexity of Each Function:
enque function:

  • Time complexity: O(N), where N is the number of elements in the deque
  • Auxiliary Space: O(N) 

 deque() method:

  • Time complexity: O(1)
  • Auxiliary Space: O(1)

getMin() method:

  • Time complexity: O(1)
  • Auxiliary Space: O(1)
     


Last Updated : 01 Nov, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads