github.com/benz9527/toy-box/algo@v0.0.0-20240221120937-66c0c6bd5abd/queue/priority_queue.go (about) 1 package queue 2 3 import ( 4 "container/heap" 5 "sync/atomic" 6 ) 7 8 // 使用最小堆来构建优先级队列 9 // 每次最小堆的根节点都会与树中最后一个叶子节点交换位置 10 // 之后剪去该叶子节点就获得了当前优先级最高的信息 11 // 剪枝的操作完成后,原本被提升为根节点的节点会被重新下沉 12 // 完成优先级的重新分布 13 // 新加入节点也会重新排列分布 14 15 type pqItem[E comparable] struct { 16 priority int64 // alignment size: 8; size: 8 17 index int64 // alignment size: 8; size: 8 18 comparator LessThan[E] // alignment size: 8; size: 8 19 value E // based on the type of E 20 } 21 22 func (item *pqItem[E]) GetPriority() int64 { 23 return atomic.LoadInt64(&item.priority) 24 } 25 26 func (item *pqItem[E]) SetPriority(priority int64) { 27 atomic.StoreInt64(&item.priority, priority) 28 } 29 30 func (item *pqItem[E]) GetIndex() int64 { 31 return atomic.LoadInt64(&item.index) 32 } 33 34 func (item *pqItem[E]) SetIndex(index int64) { 35 atomic.SwapInt64(&item.index, index) 36 } 37 38 func (item *pqItem[E]) GetValue() E { 39 return item.value 40 } 41 42 func (item *pqItem[E]) GetLessThan() LessThan[E] { 43 return item.comparator 44 } 45 46 func (item *pqItem[E]) SetLessThan(comparator LessThan[E]) { 47 if comparator == nil { 48 // default comparator, default min priority value has high priority 49 comparator = func(i, j PQItem[E]) bool { 50 return i.GetPriority() < j.GetPriority() 51 } 52 } 53 item.comparator = comparator 54 } 55 56 func NewPQItem[T comparable](value T, priority int64) PQItem[T] { 57 return &pqItem[T]{ 58 value: value, 59 priority: priority, 60 index: 0, 61 comparator: func(i, j PQItem[T]) bool { 62 // default comparator, default min priority value has high priority 63 return i.GetPriority() < j.GetPriority() 64 }, 65 } 66 } 67 68 type arrayPQ[E comparable] []PQItem[E] 69 70 func (pq *arrayPQ[E]) Len() int { 71 return len(*pq) 72 } 73 74 func (pq *arrayPQ[E]) Less(i, j int) bool { 75 // Nil panic at your own risk 76 return (*pq)[i].GetLessThan()((*pq)[i], (*pq)[j]) 77 } 78 79 func (pq *arrayPQ[E]) Swap(i, j int) { 80 (*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i] 81 (*pq)[i].SetIndex(int64(i)) 82 (*pq)[j].SetIndex(int64(j)) 83 } 84 85 func (pq *arrayPQ[E]) Pop() interface{} { 86 prev := *pq 87 n := len(prev) 88 if n <= 0 { 89 return nil 90 } 91 92 item := prev[n-1] 93 item.SetIndex(-1) 94 prev[n-1] = *new(PQItem[E]) // nil object 95 *pq = prev[:n-1] 96 return item 97 } 98 99 func (pq *arrayPQ[E]) Push(i interface{}) { 100 item, ok := i.(PQItem[E]) 101 if !ok { 102 return 103 } 104 105 prev := *pq 106 n := len(prev) 107 item.SetIndex(int64(n)) 108 *pq = append(*pq, item.(PQItem[E])) 109 } 110 111 type ArrayPriorityQueue[E comparable] struct { 112 queue arrayPQ[E] 113 localComparator LessThan[E] 114 } 115 116 // NewArrayPriorityQueue create a priority queue, you can customize the less than comparator. 117 // Default less than comparator implemented by min priority value has high priority. 118 func NewArrayPriorityQueue[E comparable]( 119 capacity int, 120 comparator ...LessThan[E], 121 ) PriorityQueue[E] { 122 if len(comparator) <= 0 { 123 comparator = []LessThan[E]{ 124 func(i, j PQItem[E]) bool { 125 return i.GetPriority() < j.GetPriority() 126 }, 127 } 128 } 129 if capacity <= 0 { 130 capacity = 32 131 } 132 pq := &ArrayPriorityQueue[E]{ 133 queue: make(arrayPQ[E], 0, capacity), 134 localComparator: comparator[0], 135 } 136 heap.Init(&pq.queue) 137 return pq 138 } 139 140 func (pq *ArrayPriorityQueue[E]) Len() int64 { 141 return int64(len(pq.queue)) 142 } 143 144 func (pq *ArrayPriorityQueue[E]) Pop() (nilItem PQItem[E]) { 145 if len(pq.queue) == 0 { 146 return nil 147 } 148 item := heap.Pop(&pq.queue) 149 return item.(PQItem[E]) 150 } 151 152 func (pq *ArrayPriorityQueue[E]) Push(item PQItem[E]) { 153 item.SetLessThan(pq.localComparator) 154 heap.Push(&pq.queue, item) 155 } 156 157 func (pq *ArrayPriorityQueue[E]) Peek() PQItem[E] { 158 if len(pq.queue) == 0 { 159 return nil 160 } 161 return pq.queue[0] 162 }