gitee.com/quant1x/gox@v1.21.2/util/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 "gitee.com/quant1x/gox/util/arraylist" 17 "gitee.com/quant1x/gox/util/internal" 18 "strings" 19 ) 20 21 func assertTreeImplementation() { 22 var _ internal.Tree = (*Heap)(nil) 23 } 24 25 // Heap holds elements in an array-list 26 type Heap struct { 27 list *arraylist.List 28 Comparator internal.Comparator 29 } 30 31 // NewWith instantiates a new empty heap tree with the custom comparator. 32 func NewWith(comparator internal.Comparator) *Heap { 33 return &Heap{list: arraylist.New(), Comparator: comparator} 34 } 35 36 // NewWithIntComparator instantiates a new empty heap with the IntComparator, i.e. elements are of type int. 37 func NewWithIntComparator() *Heap { 38 return &Heap{list: arraylist.New(), Comparator: internal.IntComparator} 39 } 40 41 // NewWithStringComparator instantiates a new empty heap with the StringComparator, i.e. elements are of type string. 42 func NewWithStringComparator() *Heap { 43 return &Heap{list: arraylist.New(), Comparator: internal.StringComparator} 44 } 45 46 // Push adds a value onto the heap and bubbles it up accordingly. 47 func (heap *Heap) Push(values ...interface{}) { 48 if len(values) == 1 { 49 heap.list.Add(values[0]) 50 heap.bubbleUp() 51 } else { 52 // Reference: https://en.wikipedia.org/wiki/Binary_heap#Building_a_heap 53 for _, value := range values { 54 heap.list.Add(value) 55 } 56 size := heap.list.Size()/2 + 1 57 for i := size; i >= 0; i-- { 58 heap.bubbleDownIndex(i) 59 } 60 } 61 } 62 63 // Pop removes top element on heap and returns it, or nil if heap is empty. 64 // Second return parameter is true, unless the heap was empty and there was nothing to pop. 65 func (heap *Heap) Pop() (value interface{}, ok bool) { 66 value, ok = heap.list.Get(0) 67 if !ok { 68 return 69 } 70 lastIndex := heap.list.Size() - 1 71 heap.list.Swap(0, lastIndex) 72 heap.list.Remove(lastIndex) 73 heap.bubbleDown() 74 return 75 } 76 77 // Peek returns top element on the heap without removing it, or nil if heap is empty. 78 // Second return parameter is true, unless the heap was empty and there was nothing to peek. 79 func (heap *Heap) Peek() (value interface{}, ok bool) { 80 return heap.list.Get(0) 81 } 82 83 // Empty returns true if heap does not contain any elements. 84 func (heap *Heap) Empty() bool { 85 return heap.list.Empty() 86 } 87 88 // Size returns number of elements within the heap. 89 func (heap *Heap) Size() int { 90 return heap.list.Size() 91 } 92 93 // Clear removes all elements from the heap. 94 func (heap *Heap) Clear() { 95 heap.list.Clear() 96 } 97 98 // Values returns all elements in the heap. 99 func (heap *Heap) Values() []interface{} { 100 return heap.list.Values() 101 } 102 103 // String returns a string representation of container 104 func (heap *Heap) String() string { 105 str := "BinaryHeap\n" 106 values := []string{} 107 for _, value := range heap.list.Values() { 108 values = append(values, fmt.Sprintf("%v", value)) 109 } 110 str += strings.Join(values, ", ") 111 return str 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) 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) 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) 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) withinRange(index int) bool { 161 return index >= 0 && index < heap.list.Size() 162 }