Open In App

Extracting last element of a Priority Queue without traversing

Improve
Improve
Like Article
Like
Save
Share
Report

The Task is to extract the last element of the priority queue without traversing it.

Approach:

This problem can be solved using a Double-ended priority queue, a double-ended priority queue supports operations of both max heap (a max priority queue) and min heap (a min priority queue).

The operations are:

  • getMax(): Returns maximum element.
  • getMin(): Returns minimum element.
  • deleteMax(): Deletes maximum element.
  • deleteMin(): Deletes minimum element.
  • size(): Returns count of elements.
  • isEmpty(): Returns true if the queue is empty.

Approach to Extract the last element of a priority queue without traversing:

We can use the following two data structures to implement the functionality.

Linked Lists:

We can try using a linked list. In the case of a linked list, if we maintain elements in sorted order, then the time complexity of all operations becomes O(1) except the operation insert() which takes O(n) time.

Heaps:

We can try to use two heaps (min heap and max heap). The main idea is to maintain one-to-one correspondence, so that deleteMin() and deleteMax() can be done in O(log n) time. The heap-based solution requires O(n) extra space for an extra heap. The advantage of a heap-based solution is cache friendly.

  • We maintain a pointer of every max heap element in the min heap. 
  • To get the minimum element, we simply return the root. 
  • To get the maximum element, we return the root of the max heap. 
  • To insert an element, we insert it in the min heap and max heap. 

Self-Balancing Binary Search Tree:

We will here implement a double-ended priority queue using a self-balancing binary search tree.  A self-balancing BST is implemented as set in C++ and TreeSet in Java. Follow the below steps to implement a priority queue where we can get the last element without traversing.

  • Create a struct class named DblEndedPQ that holds all operations of a double-ended priority queue.
  • Initialize a multiset st. [ We are using multiset because elements inserted inside multiset sort automatically like a priority queue, according to need.]
  • Then, create mandatory operations like:
    • size()
    • isEmpty(),
    • insert(),
    • getMin()
    • getMax()
    • getMin()
    • deleteMin()
    • deleteMax()

Below is the Implementation of the above approach:

C++




// C++ program to implement double-ended
// priority queue using self balancing BST.
 
#include <bits/stdc++.h>
using namespace std;
 
// Structure of double-ended priority queue
struct DblEndedPQ {
    multiset<int> st;
 
    // Returns size of the queue. Works in
    // O(1) time
    int size() { return st.size(); }
 
    // Returns true if queue is empty.
    // Works in O(1) time
    bool isEmpty() { return (st.size() == 0); }
 
    // Inserts an element.
    // Works in O(log n) time
    void insert(int x) { st.insert(x); }
 
    // Returns minimum element.
    // Works in O(1) time
    int getMin() { return *(st.begin()); }
 
    // Returns maximum element.
    // Works in O(1) time
    int getMax() { return *(st.rbegin()); }
 
    // Deletes the minimum element.
    // Works in O(log n) time
    void deleteMin()
    {
        if (st.size() == 0)
            return;
 
        auto it = st.begin();
        st.erase(it);
    }
 
    // Deletes the maximum element.
    // Works in O(log n) time
    void deleteMax()
    {
        if (st.size() == 0)
            return;
 
        auto it = st.end();
        it--;
        st.erase(it);
    }
};
 
// Driver code
int main()
{
    DblEndedPQ d;
 
    d.insert(10);
    d.insert(20);
    d.insert(40);
    d.insert(30);
 
    cout << "Minimum Element is: " << d.getMin() << endl;
    cout << "Maximum Element is: " << d.getMax() << endl;
 
    d.deleteMin();
    cout << "Minimum Element is: " << d.getMin() << endl;
 
    d.deleteMax();
    cout << "Maximum Element is: " << d.getMax() << endl;
 
    cout << "Size of DblEndedPQ is: " << d.size() << endl;
 
    cout << "Is DblEndedPQ empty: "
         << (d.isEmpty() ? "YES" : "NO") << endl;
 
    return 0;
}


Java




import java.util.Set;
import java.util.TreeSet;
 
public class DblEndedPQ {
    Set<Integer> st;
 
    DblEndedPQ() {
        st = new TreeSet<>();
    }
 
    int size() {
        return st.size();
    }
 
    boolean isEmpty() {
        return (st.size() == 0);
    }
 
    void insert(int x) {
        st.add(x);
    }
 
    int getMin() {
        if (st.isEmpty()) {
            return Integer.MIN_VALUE;
        }
        return st.iterator().next();
    }
 
    int getMax() {
        if (st.isEmpty()) {
            return Integer.MIN_VALUE;
        }
        return ((TreeSet<Integer>) st).last();
    }
 
    void deleteMin() {
        if (st.size() == 0)
            return;
 
        st.remove(getMin());
    }
 
    void deleteMax() {
        if (st.size() == 0)
            return;
 
        st.remove(getMax());
    }
 
    public static void main(String[] args) {
        DblEndedPQ d = new DblEndedPQ();
 
        d.insert(10);
        d.insert(20);
        d.insert(40);
        d.insert(30);
 
        System.out.println("Minimum Element is: " + d.getMin());
        System.out.println("Maximum Element is: " + d.getMax());
 
        d.deleteMin();
        System.out.println("Minimum Element is: " + d.getMin());
 
        d.deleteMax();
        System.out.println("Maximum Element is: " + d.getMax());
 
        System.out.println("Size of DblEndedPQ is: " + d.size());
 
        System.out.println("Is DblEndedPQ empty: "
                + (d.isEmpty() ? "YES" : "NO"));
    }
}


Python3




import bisect
 
class DblEndedPQ:
    def __init__(self):
        self.st = []
         
    def size(self):
        return len(self.st)
     
    def isEmpty(self):
        return self.size() == 0
     
    def insert(self, x):
        bisect.insort(self.st, x)
     
    def getMin(self):
        return self.st[0]
     
    def getMax(self):
        return self.st[-1]
     
    def deleteMin(self):
        if self.isEmpty():
            return
        self.st.pop(0)
     
    def deleteMax(self):
        if self.isEmpty():
            return
        self.st.pop()
         
 
# Driver code
d = DblEndedPQ()
 
d.insert(10)
d.insert(20)
d.insert(40)
d.insert(30)
 
print("Minimum Element is: ", d.getMin())
print("Maximum Element is: ", d.getMax())
 
d.deleteMin()
print("Minimum Element is: ", d.getMin())
 
d.deleteMax()
print("Maximum Element is: ", d.getMax())
 
print("Size of DblEndedPQ is: ", d.size())
 
print("Is DblEndedPQ empty: ", "YES" if d.isEmpty() else "NO")


C#




using System;
using System.Collections.Generic;
 
// Class to implement double-ended priority queue using SortedSet
class DblEndedPQ
{
    // SortedSet to store elements in the queue
    SortedSet<int> st = new SortedSet<int>();
 
    // Method to return the size of the queue
    public int Size()
    {
        return st.Count;
    }
 
    // Method to check if the queue is empty
    public bool IsEmpty()
    {
        return st.Count == 0;
    }
 
    // Method to insert an element into the queue
    public void Insert(int x)
    {
        st.Add(x);
    }
 
    // Method to return the minimum element in the queue
    public int GetMin()
    {
        return st.Min;
    }
 
    // Method to return the maximum element in the queue
    public int GetMax()
    {
        return st.Max;
    }
 
    // Method to delete the minimum element in the queue
    public void DeleteMin()
    {
        if (st.Count == 0)
            return;
 
        st.Remove(st.Min);
    }
 
    // Method to delete the maximum element in the queue
    public void DeleteMax()
    {
        if (st.Count == 0)
            return;
 
        st.Remove(st.Max);
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        DblEndedPQ d = new DblEndedPQ();
 
        // Inserting elements into the queue
        d.Insert(10);
        d.Insert(20);
        d.Insert(40);
        d.Insert(30);
 
        // Printing minimum and maximum elements
        Console.WriteLine("Minimum Element is: " + d.GetMin());
        Console.WriteLine("Maximum Element is: " + d.GetMax());
 
        // Deleting the minimum element
        d.DeleteMin();
        Console.WriteLine("Minimum Element is: " + d.GetMin());
 
        // Deleting the maximum element
        d.DeleteMax();
        Console.WriteLine("Maximum Element is: " + d.GetMax());
 
        // Printing the size of the queue
        Console.WriteLine("Size of DblEndedPQ is: " + d.Size());
 
        // Printing if the queue is empty or not
        Console.WriteLine("Is DblEndedPQ empty: " + (d.IsEmpty() ? "YES" : "NO"));
    }
}


Javascript




class DblEndedPQ {
  constructor() {
    this.st = new Set();
  }
 
  size() {
    return this.st.size;
  }
 
  isEmpty() {
    return this.st.size === 0;
  }
 
  insert(x) {
    this.st.add(x);
  }
 
  getMin() {
    return Math.min(...this.st);
  }
 
  getMax() {
    return Math.max(...this.st);
  }
 
  deleteMin() {
    if (this.st.size === 0) return;
    this.st.delete(Math.min(...this.st));
  }
 
  deleteMax() {
    if (this.st.size === 0) return;
    this.st.delete(Math.max(...this.st));
  }
}
 
const d = new DblEndedPQ();
 
d.insert(10);
d.insert(20);
d.insert(40);
d.insert(30);
 
console.log("Minimum Element is: " + d.getMin());
console.log("Maximum Element is: " + d.getMax());
 
d.deleteMin();
console.log("Minimum Element is: " + d.getMin());
 
d.deleteMax();
console.log("Maximum Element is: " + d.getMax());
 
console.log("Size of DblEndedPQ is: " + d.size());
 
console.log("Is DblEndedPQ empty: " + (d.isEmpty() ? "YES" : "NO"));


Output

Minimum Element is: 10
Maximum Element is: 40
Minimum Element is: 20
Maximum Element is: 30
Size of DblEndedPQ is: 2
Is DblEndedPQ empty: NO

Time Complexity:

  • getMax() : O(1)
  • getMin() : O(1)
  • deleteMax() : O(Log n)
  • deleteMin() : O(Log n)
  • size() : O(1)
  • isEmpty() : O(1)

Auxiliary Space: O(N)

Related Articles:



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