Golang Program to Implement a Binary Heap Using a Linked List


A binary heap is a specialized tree-based data structure that satisfies the heap property, where the key of each node is either greater than or equal to (in a max heap) or less than or equal to (in a min heap) the keys of its children. In this program, we utilize a linked list to represent the binary heap.

In this article, we will learn how to develop the Golang program to implement a binary heap using a linked list. Here we are going to use four different methods singly linked list, doubly linked list, custom node struct, and slice-based implementation along with examples to elaborate the concept.

Syntax

heap.insert(value)

This method is used to implement the insertion operation to a heap data structure.

value − It is the value that you need to insert to the heap.

heap.delete()

This method is used to delete the top element of the top element from the heap, that is sometimes the minimum element or the maximum element depending upon the type of the heap.

Example 1

In a Singly Linked List, each node has a single reference pointing to the next node, and the last node points to null, indicating the end of the list. The first node in the list is called the head, and it serves as the entry point for accessing the list.This code implements a binary heap using a singly linked list. Insert method: Inserts a new value into the binary heap by creating a new node with the given value and setting its next pointer to the current head of the list. Delete method: Deletes the root element from the binary heap by updating the head pointer to point to the next node in the list, effectively removing the current head.Print method: Prints the elements of the binary heap by traversing the linked list starting from the head node and printing each node's value.

package main

import (
   "fmt"
)

type Node struct {
   value int
   next  *Node
}

type Heap struct {
   head *Node
}

func (h *Heap) Insert(value int) {
   newNode := &Node{
      value: value,
      next:  h.head,
   }
   h.head = newNode
}

func (h *Heap) Delete() {
   if h.head == nil {
      return
   }
   h.head = h.head.next
}

func (h *Heap) Print() {
   current := h.head
   for current != nil {
      fmt.Printf("%d ", current.value)
      current = current.next
   }
   fmt.Println()
}

func main() {
   heap := &Heap{}
   heap.Insert(10)
   heap.Insert(20)
   heap.Insert(30)
   heap.Insert(40)

   fmt.Println("Elements in the binary heap:")
   heap.Print()

   heap.Delete()

   fmt.Println("Elements after deleting from the binary heap:")
   heap.Print()
}

Output

Elements in the binary heap:
40 30 20 10 
Elements after deleting from the binary heap:
30 20 10 

Example 2

In this Example, a doubly linked list is used to implement a binary heap. A doubly linked list is a linear data structure where each node contains a value and two pointers, one pointing to the previous node and another pointing to the next node. This code implements a binary heap using a doubly linked list. Insert method: Inserts a new value into the binary heap by creating a new node with the given value. The new node's next pointer is set to the current head of the list, and its prev pointer is set to nil. Delete method: Deletes the root element from the binary heap by updating the head pointer to point to the next node in the listPrint method: Prints the elements of the binary heap by traversing the linked list starting from the head node and printing each node's value.

package main

import (
   "fmt"
)

type Node struct {
   value int
   prev  *Node
   next  *Node
}

type Heap struct {
   head *Node
}

func (h *Heap) Insert(value int) {
   newNode := &Node{
      value: value,
      prev:  nil,
      next:  h.head,
   }
   if h.head != nil {
      h.head.prev = newNode
   }
   h.head = newNode
}

func (h *Heap) Delete() {
   if h.head == nil {
      return
   }
   h.head = h.head.next
   if h.head != nil {
      h.head.prev = nil
   }
}

func (h *Heap) Print() {
   current := h.head
   for current != nil {
      fmt.Printf("%d ", current.value)
      current = current.next
   }
   fmt.Println()
}

func main() {
   heap := &Heap{}
   heap.Insert(10)
   heap.Insert(20)
   heap.Insert(30)
   heap.Insert(40)

   fmt.Println("Elements in the binary heap:")
   heap.Print()

   heap.Delete()

   fmt.Println("Elements after deleting from the binary heap:")
   heap.Print()
}

Output

Elements in the binary heap:
40 30 20 10 
Elements after deleting from the binary heap:
30 20 10

Example 3

This code implements a binary heap using a slice-based implementation. This implementation of a binary heap using a slice-based implementation offers efficient insertion and deletion operations with time complexity of O(log N) in the worst case, where N is the number of elements in the heap. The heapifyUp and heapifyDown functions ensure that the heap property is maintained after each operation.

package main

import (
   "fmt"
)

type Heap struct {
   array []int
}

func (h *Heap) Insert(value int) {
   h.array = append(h.array, value)
   h.heapifyUp(len(h.array) - 1)
}

func (h *Heap) Delete() {
   if len(h.array) == 0 {
      return
   }
   h.array[0] = h.array[len(h.array)-1]
   h.array = h.array[:len(h.array)-1]
   h.heapifyDown(0)
}

func (h *Heap) Print() {
   fmt.Println(h.array)
}

func (h *Heap) heapifyUp(index int) {
   parent := (index - 1) / 2
   for index > 0 && h.array[index] > h.array[parent] {
      h.array[index], h.array[parent] = h.array[parent], h.array[index]
      index = parent
      parent = (index - 1) / 2
   }
}

func (h *Heap) heapifyDown(index int) {
   n := len(h.array)
   largest := index
   left := 2*index + 1
   right := 2*index + 2

   if left < n && h.array[left] > h.array[largest] {
      largest = left
   }
   if right < n && h.array[right] > h.array[largest] {
      largest = right
   }

   if largest != index {
      h.array[index], h.array[largest] = h.array[largest], h.array[index]
      h.heapifyDown(largest)
   }
}

func main() {
   heap := &Heap{}
   heap.Insert(10)
   heap.Insert(20)
   heap.Insert(30)
   heap.Insert(40)

   fmt.Println("Elements in the binary heap:")
   heap.Print()

   heap.Delete()

   fmt.Println("Elements after deleting from the binary heap:")
   heap.Print()
}

Output

Elements in the binary heap:
[40 30 20 10]
Elements after deleting from the binary heap:
[30 10 20]

Conclusion

In Conclusion, here we have provided different methods to represent and manipulate the binary heap data structure, such as singly linked list, doubly linked list, custom node struct, and slice-based implementation. By implementing the binary heap using a linked list, the program offers efficient insertion and deletion operations with a time complexity of O(log n). It provides a flexible and dynamic data structure for managing a collection of elements with the ability to efficiently maintain the heap property.

Updated on: 20-Jul-2023

223 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements