Extracting last element of a Priority Queue without traversing
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" )); |
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:
- What is Priority Queue | Introduction to Priority Queue
- Heap Data Structure
- Multiset in C++ Standard Template Library (STL)
- Introduction to Binary Search Tree – Data Structures and Algorithms Tutorials
Please Login to comment...