Golang program to implement a double ended priority queue


A Double Ended Priority Queue, in short DEPQ is a data structure that extends the functionality of a standard priority queue. In this article, we will implement a double ended priority queue in Golang using two methods: the first method uses two separate heaps for maximum and minimum priorities, while the second method augments a single heap with additional information for efficient queries. In the code examples we are going to perform the operations like insertion retrieval, deletion and updation.

Explanation

Double ended priority queue is a data structure that allows insertion and deletion operations and it allows efficient access to both maximum and minimum elements in collection.

Max Heap:       Min Heap:
   9                3
  / \              /  \
 7   5            4    6
/                /
3               5

In the max heap, root contain max value [9], each parent node has value greater than the child node, and as you go down from top to bottom the values decrease.

In the min heap, the root node contains the smallest value [3], each parent node has the value greater than the children, and as you go top to bottom the value increases.

Algorithm

  • Initialize two heaps, maxHeap and minHeap.

  • Compare the element with the roots of maxHeap and minHeap to determine its priority.Insert the element into the corresponding heap. Balance the heaps if the size difference exceeds 1.

  • Delete the element from the heap that contains it. Balance the heaps if the size difference exceeds 1.

  • Return the root of maxHeap.

  • Return the root of minHeap.

Syntax

type DEPQ struct {
	maxHeap, minHeap []int
}

The DEPQ struct contains both maxHeap and minHeap slices, allowing efficient retrieval of the highest and lowest priority elements.

type DEPQ struct {
	heap   []int
	values map[int]int
}

The syntax implements a DEPQ using a single augmented heap. The DEPQ struct contains two slices: heap to store the elements in the priority queue and values to keep track of the elements' positions. The AugmentedHeap struct contains the heap slice, allowing for efficient queries to find both the highest and lowest priority elements.

Example 1

In this example, we implement a Double Ended Priority Queue in go using two separate heaps, one for the maximum priority (maxHeap) and the other for the minimum priority (minHeap). The Insert function inserts elements into both heaps, while the Delete function removes elements from both heaps. The GetMax and GetMin functions retrieve the maximum and minimum elements, respectively, from the DEPQ.

package main

import (
	"container/heap"
	"fmt"
)

type MaxHeap []int

func (h MaxHeap) Len() int            { return len(h) }
func (h MaxHeap) Less(i, j int) bool  { return h[i] > h[j] }
func (h MaxHeap) Swap(i, j int)       { h[i], h[j] = h[j], h[i] }
func (h *MaxHeap) Push(x interface{}) { *h = append(*h, x.(int)) }
func (h *MaxHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

type MinHeap []int

func (h MinHeap) Len() int            { return len(h) }
func (h MinHeap) Less(i, j int) bool  { return h[i] < h[j] }
func (h MinHeap) Swap(i, j int)       { h[i], h[j] = h[j], h[i] }
func (h *MinHeap) Push(x interface{}) { *h = append(*h, x.(int)) }
func (h *MinHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

type DEPQ struct {
	maxHeap *MaxHeap
	minHeap *MinHeap
}

func NewDEPQ() *DEPQ {
	maxHeap := &MaxHeap{}
	minHeap := &MinHeap{}
	heap.Init(maxHeap)
	heap.Init(minHeap)
	return &DEPQ{maxHeap, minHeap}
}

func (dq *DEPQ) Insert(val int) {
	heap.Push(dq.maxHeap, val)
	heap.Push(dq.minHeap, val)
}

func (dq *DEPQ) Delete(val int) {
	for i := 0; i < len(*dq.maxHeap); i++ {
		if (*dq.maxHeap)[i] == val {
			heap.Remove(dq.maxHeap, i)
			break
		}
	}
	for i := 0; i < len(*dq.minHeap); i++ {
		if (*dq.minHeap)[i] == val {
			heap.Remove(dq.minHeap, i)
			break
		}
	}
}

func (dq *DEPQ) GetMax() int {
	if len(*dq.maxHeap) > 0 {
		return (*dq.maxHeap)[0]
	}
	return -1
}

func (dq *DEPQ) GetMin() int {
	if len(*dq.minHeap) > 0 {
		return (*dq.minHeap)[0]
	}
	return -1
}

func main() {
	dq := NewDEPQ()

	dq.Insert(5)
	dq.Insert(3)
	dq.Insert(7)
	dq.Insert(4)
	dq.Insert(6)

	fmt.Println("Maximum element:", dq.GetMax()) 
	fmt.Println("Minimum element:", dq.GetMin()) 

	dq.Delete(4)

	fmt.Println("Maximum element after deletion:", dq.GetMax()) 	
        fmt.Println("Minimum element after deletion:", dq.GetMin()) 
}

Output

Maximum element: 7
Minimum element: 3
Maximum element after deletion: 7
Minimum element after deletion: 3

Example 2

In this example, we use a single heap to represent the Double Ended Priority Queue in go. Each element is stored twice in the heap, once as a maximum element and once as a minimum element, using the DEPQNode struct. The DEPQ struct contains the heap and a unique identifier to ensure each node has a distinct identifier. The Insert function adds elements to the DEPQ by creating two DEPQNode instances, one for maximum and one for minimum, and adding them to the heap. The GetMaximum and GetMinimum functions retrieve the maximum and minimum elements from the DEPQ, respectively. The Remove function removes the specified element from the DEPQ by finding and removing both occurrences of the element in the heap.

package main

import (
	"container/heap"
	"fmt"
)
type DEPQNode struct {
	value       int
	isMax, isMin bool
	uniqueID    int
}
type DEPQHeap []DEPQNode

func NewDEPQHeap() *DEPQHeap {
	return &DEPQHeap{}
}

func (h DEPQHeap) Len() int           { return len(h) }
func (h DEPQHeap) Less(i, j int) bool { return h[i].value < h[j].value }
func (h DEPQHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *DEPQHeap) Push(x interface{}) {
	node := x.(DEPQNode)
	*h = append(*h, node)
}

func (h *DEPQHeap) Pop() interface{} {
	old := *h
	n := len(old)
	node := old[n-1]
	*h = old[0 : n-1]
	return node
}

type DoubleEndedPriorityQueue struct {
	heap *DEPQHeap
}
func NewDoubleEndedPriorityQueue() *DoubleEndedPriorityQueue {
	return &DoubleEndedPriorityQueue{
		heap: NewDEPQHeap(),
	}
}
func (dePQ *DoubleEndedPriorityQueue) Insert(value int) {
	node := DEPQNode{value: value, isMax: true, isMin: true, uniqueID: len(*dePQ.heap)}
	heap.Push(dePQ.heap, node)
}

func (dePQ *DoubleEndedPriorityQueue) GetMinimum() int {
	if dePQ.heap.Len() == 0 {
		return -1 
	}
	return (*dePQ.heap)[0].value
}

func (dePQ *DoubleEndedPriorityQueue) GetMaximum() int {
	if dePQ.heap.Len() == 0 {
		return -1 
	}
	return (*dePQ.heap)[dePQ.heap.Len()-1].value
}

func main() {
	dePQ := NewDoubleEndedPriorityQueue()

	dePQ.Insert(10)
	dePQ.Insert(5)
	dePQ.Insert(20)

	fmt.Println("Minimum Element:", dePQ.GetMinimum())
	fmt.Println("Maximum Element:", dePQ.GetMaximum()) 
}

Output

Minimum Element: 5
Maximum Element: 20

Real life Implementations

Hospital Patient Management

In a hospital, patient triage involves prioritizing patients based on their medical condition. A DEPQ could store patients with the most severe illnesses at the top (using max-heap) and patients with less severe conditions at the bottom (using min-heap). This enables doctors to quickly attend to critical patients while also efficiently managing less urgent cases.

Social Media Feeds

Social media platforms often display posts based on user engagement. A DEPQ could prioritize posts with the highest likes or comments at the top (using max-heap) and less popular posts at the bottom (using min-heap). This allows users to see both trending content and less prominent posts in their feeds, enhancing their browsing experience.

Conclusion

DEPQ is an extension of the standard priority queue, allowing efficient retrieval of both the highest and lowest priority elements. In this article, we will explore two methods to implement a Double Ended Priority Queue in go. The first method used two separate heaps for maximum and minimum priorities, while the second method utilised a single augmented heap. The code examples illustrated the insertion, deletion, and retrieval of elements in the DEPQ, showcasing their practical applications and efficiency.

Updated on: 05-Sep-2023

88 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements