github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/trees/binaryheap/binaryheap.go (about)

     1  // Package binaryheap implements a binary heap backed by array list.
     2  //
     3  // Comparator defines this heap as either min or max heap.
     4  //
     5  // Structure is not thread safe.
     6  //
     7  // References: http://en.wikipedia.org/wiki/Binary_heap
     8  package binaryheap
     9  
    10  import (
    11  	"fmt"
    12  	"github.com/songzhibin97/go-baseutils/base/bcomparator"
    13  	"github.com/songzhibin97/go-baseutils/structure/lists/arraylist"
    14  	"github.com/songzhibin97/go-baseutils/structure/trees"
    15  
    16  	"strings"
    17  )
    18  
    19  // Assert Tree implementation
    20  var _ trees.Tree[any] = (*Heap[any])(nil)
    21  
    22  // Heap holds elements in an array-list
    23  type Heap[E any] struct {
    24  	list       *arraylist.List[E]
    25  	Comparator bcomparator.Comparator[E]
    26  }
    27  
    28  // NewWith instantiates a new empty heap tree with the custom comparator.
    29  func NewWith[E any](comparator bcomparator.Comparator[E]) *Heap[E] {
    30  	return &Heap[E]{list: arraylist.New[E](), Comparator: comparator}
    31  }
    32  
    33  // NewWithIntComparator instantiates a new empty heap with the IntComparator, i.e. elements are of type int.
    34  func NewWithIntComparator() *Heap[int] {
    35  	return &Heap[int]{list: arraylist.New[int](), Comparator: bcomparator.IntComparator()}
    36  }
    37  
    38  // NewWithStringComparator instantiates a new empty heap with the StringComparator, i.e. elements are of type string.
    39  func NewWithStringComparator() *Heap[string] {
    40  	return &Heap[string]{list: arraylist.New[string](), Comparator: bcomparator.StringComparator()}
    41  }
    42  
    43  // Push adds a value onto the heap and bubbles it up accordingly.
    44  func (heap *Heap[E]) Push(values ...E) {
    45  	if len(values) == 1 {
    46  		heap.list.Add(values[0])
    47  		heap.bubbleUp()
    48  	} else {
    49  		// Reference: https://en.wikipedia.org/wiki/Binary_heap#Building_a_heap
    50  		for _, value := range values {
    51  			heap.list.Add(value)
    52  		}
    53  		size := heap.list.Size()/2 + 1
    54  		for i := size; i >= 0; i-- {
    55  			heap.bubbleDownIndex(i)
    56  		}
    57  	}
    58  }
    59  
    60  // Pop removes top element on heap and returns it, or nil if heap is empty.
    61  // Second return parameter is true, unless the heap was empty and there was nothing to pop.
    62  func (heap *Heap[E]) Pop() (value E, ok bool) {
    63  	value, ok = heap.list.Get(0)
    64  	if !ok {
    65  		return
    66  	}
    67  	lastIndex := heap.list.Size() - 1
    68  	heap.list.Swap(0, lastIndex)
    69  	heap.list.Remove(lastIndex)
    70  	heap.bubbleDown()
    71  	return
    72  }
    73  
    74  // Peek returns top element on the heap without removing it, or nil if heap is empty.
    75  // Second return parameter is true, unless the heap was empty and there was nothing to peek.
    76  func (heap *Heap[E]) Peek() (value E, ok bool) {
    77  	return heap.list.Get(0)
    78  }
    79  
    80  // Empty returns true if heap does not contain any elements.
    81  func (heap *Heap[E]) Empty() bool {
    82  	return heap.list.Empty()
    83  }
    84  
    85  // Size returns number of elements within the heap.
    86  func (heap *Heap[E]) Size() int {
    87  	return heap.list.Size()
    88  }
    89  
    90  // Clear removes all elements from the heap.
    91  func (heap *Heap[E]) Clear() {
    92  	heap.list.Clear()
    93  }
    94  
    95  // Values returns all elements in the heap.
    96  func (heap *Heap[E]) Values() []E {
    97  	values := make([]E, heap.list.Size(), heap.list.Size())
    98  	for it := heap.Iterator(); it.Next(); {
    99  		values[it.Index()] = it.Value()
   100  	}
   101  	return values
   102  }
   103  
   104  // String returns a string representation of container
   105  func (heap *Heap[E]) String() string {
   106  	b := strings.Builder{}
   107  	b.WriteString("BinaryHeap\n")
   108  	for it := heap.Iterator(); it.Next(); {
   109  		b.WriteString(fmt.Sprintf("(value:%v) ", it.Value()))
   110  	}
   111  	return b.String()
   112  }
   113  
   114  // Performs the "bubble down" operation. This is to place the element that is at the root
   115  // of the heap in its correct place so that the heap maintains the min/max-heap order property.
   116  func (heap *Heap[E]) bubbleDown() {
   117  	heap.bubbleDownIndex(0)
   118  }
   119  
   120  // Performs the "bubble down" operation. This is to place the element that is at the index
   121  // of the heap in its correct place so that the heap maintains the min/max-heap order property.
   122  func (heap *Heap[E]) bubbleDownIndex(index int) {
   123  	size := heap.list.Size()
   124  	for leftIndex := index<<1 + 1; leftIndex < size; leftIndex = index<<1 + 1 {
   125  		rightIndex := index<<1 + 2
   126  		smallerIndex := leftIndex
   127  		leftValue, _ := heap.list.Get(leftIndex)
   128  		rightValue, _ := heap.list.Get(rightIndex)
   129  		if rightIndex < size && heap.Comparator(leftValue, rightValue) > 0 {
   130  			smallerIndex = rightIndex
   131  		}
   132  		indexValue, _ := heap.list.Get(index)
   133  		smallerValue, _ := heap.list.Get(smallerIndex)
   134  		if heap.Comparator(indexValue, smallerValue) > 0 {
   135  			heap.list.Swap(index, smallerIndex)
   136  		} else {
   137  			break
   138  		}
   139  		index = smallerIndex
   140  	}
   141  }
   142  
   143  // Performs the "bubble up" operation. This is to place a newly inserted
   144  // element (i.e. last element in the list) in its correct place so that
   145  // the heap maintains the min/max-heap order property.
   146  func (heap *Heap[E]) bubbleUp() {
   147  	index := heap.list.Size() - 1
   148  	for parentIndex := (index - 1) >> 1; index > 0; parentIndex = (index - 1) >> 1 {
   149  		indexValue, _ := heap.list.Get(index)
   150  		parentValue, _ := heap.list.Get(parentIndex)
   151  		if heap.Comparator(parentValue, indexValue) <= 0 {
   152  			break
   153  		}
   154  		heap.list.Swap(index, parentIndex)
   155  		index = parentIndex
   156  	}
   157  }
   158  
   159  // Check that the index is within bounds of the list
   160  func (heap *Heap[E]) withinRange(index int) bool {
   161  	return index >= 0 && index < heap.list.Size()
   162  }
   163  
   164  // UnmarshalJSON @implements json.Unmarshaler
   165  func (heap *Heap[E]) UnmarshalJSON(bytes []byte) error {
   166  	return heap.list.UnmarshalJSON(bytes)
   167  }
   168  
   169  // MarshalJSON @implements json.Marshaler
   170  func (heap *Heap[E]) MarshalJSON() ([]byte, error) {
   171  	return heap.list.MarshalJSON()
   172  }