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