priorityqueue.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // modified from github.com/oleiade/lane
  2. package pq
  3. import (
  4. "golang.org/x/exp/constraints"
  5. )
  6. // PriorityQueue is a heap-based priority-queue data structure implementation.
  7. //
  8. // It can either be min (ascending) or max (descending)
  9. // oriented/ordered. Its type parameters `T` and `P`, respectively
  10. // specify the underlying value type and the underlying priority type.
  11. type PriorityQueue[T any, P constraints.Ordered] struct {
  12. items []*priorityQueueItem[T, P]
  13. itemCount uint
  14. comparator func(lhs, rhs P) bool
  15. }
  16. // NewPriorityQueue instantiates a new PriorityQueue with the provided comparison heuristic.
  17. // The package defines the `Max` and `Min` heuristic to define a max-oriented or
  18. // min-oriented heuristics, respectively.
  19. func NewPriorityQueue[T any, P constraints.Ordered](heuristic func(lhs, rhs P) bool) *PriorityQueue[T, P] {
  20. items := make([]*priorityQueueItem[T, P], 1)
  21. items[0] = nil
  22. return &PriorityQueue[T, P]{
  23. items: items,
  24. itemCount: 0,
  25. comparator: heuristic,
  26. }
  27. }
  28. // NewMaxPriorityQueue instantiates a new maximum oriented PriorityQueue.
  29. func NewMaxPriorityQueue[T any, P constraints.Ordered]() *PriorityQueue[T, P] {
  30. return NewPriorityQueue[T](Maximum[P])
  31. }
  32. // NewMinPriorityQueue instantiates a new minimum oriented PriorityQueue.
  33. func NewMinPriorityQueue[T any, P constraints.Ordered]() *PriorityQueue[T, P] {
  34. return NewPriorityQueue[T](Minimum[P])
  35. }
  36. // Maximum returns whether `rhs` is greater than `lhs`.
  37. //
  38. // Use it as a comparison heuristic during a PriorityQueue's
  39. // instantiation.
  40. func Maximum[T constraints.Ordered](lhs, rhs T) bool {
  41. return lhs < rhs
  42. }
  43. // Minimum returns whether `rhs` is less than `lhs`.
  44. //
  45. // Use it as a comparison heuristic during a PriorityQueue's
  46. // instantiation.
  47. func Minimum[T constraints.Ordered](lhs, rhs T) bool {
  48. return lhs > rhs
  49. }
  50. // Push inserts the value in the PriorityQueue with the provided priority
  51. // in at most *O(log n)* time complexity.
  52. func (pq *PriorityQueue[T, P]) Push(value T, priority P) {
  53. item := newPriorityQueueItem(value, priority)
  54. pq.items = append(pq.items, item)
  55. pq.itemCount++
  56. pq.swim(pq.size())
  57. }
  58. // Pop and return the highest or lowest priority item (depending on the
  59. // comparison heuristic of your PriorityQueue) from the PriorityQueue in
  60. // at most *O(log n)* complexity.
  61. func (pq *PriorityQueue[T, P]) Pop() (value T, priority P, ok bool) {
  62. if pq.size() < 1 {
  63. ok = false
  64. return
  65. }
  66. max := pq.items[1]
  67. pq.exch(1, pq.size())
  68. pq.items = pq.items[0:pq.size()]
  69. pq.itemCount--
  70. pq.sink(1)
  71. value = max.value
  72. priority = max.priority
  73. ok = true
  74. return
  75. }
  76. // Head returns the highest or lowest priority item (depending on
  77. // the comparison heuristic of your PriorityQueue) from the PriorityQueue
  78. // in *O(1)* complexity.
  79. func (pq *PriorityQueue[T, P]) Head() (value T, priority P, ok bool) {
  80. if pq.size() < 1 {
  81. ok = false
  82. return
  83. }
  84. value = pq.items[1].value
  85. priority = pq.items[1].priority
  86. ok = true
  87. return
  88. }
  89. // Size returns the number of elements present in the PriorityQueue.
  90. func (pq *PriorityQueue[T, P]) Size() uint {
  91. return pq.size()
  92. }
  93. // Empty returns whether the PriorityQueue is empty.
  94. func (pq *PriorityQueue[T, P]) Empty() bool {
  95. return pq.size() == 0
  96. }
  97. // Clone returns a copy of the PriorityQueue.
  98. func (pq *PriorityQueue[T, P]) Clone() *PriorityQueue[T, P] {
  99. items := make([]*priorityQueueItem[T, P], len(pq.items))
  100. copy(items, pq.items)
  101. return &PriorityQueue[T, P]{
  102. items: items,
  103. itemCount: pq.itemCount,
  104. comparator: pq.comparator,
  105. }
  106. }
  107. func (pq *PriorityQueue[T, P]) swim(k uint) {
  108. for k > 1 && pq.less(k/2, k) {
  109. pq.exch(k/2, k)
  110. k /= 2
  111. }
  112. }
  113. func (pq *PriorityQueue[T, P]) sink(k uint) {
  114. for 2*k <= pq.size() {
  115. j := 2 * k
  116. if j < pq.size() && pq.less(j, j+1) {
  117. j++
  118. }
  119. if !pq.less(k, j) {
  120. break
  121. }
  122. pq.exch(k, j)
  123. k = j
  124. }
  125. }
  126. func (pq *PriorityQueue[T, P]) size() uint {
  127. return pq.itemCount
  128. }
  129. func (pq *PriorityQueue[T, P]) less(lhs, rhs uint) bool {
  130. return pq.comparator(pq.items[lhs].priority, pq.items[rhs].priority)
  131. }
  132. func (pq *PriorityQueue[T, P]) exch(lhs, rhs uint) {
  133. pq.items[lhs], pq.items[rhs] = pq.items[rhs], pq.items[lhs]
  134. }
  135. // priorityQueueItem is the underlying PriorityQueue item container.
  136. type priorityQueueItem[T any, P constraints.Ordered] struct {
  137. value T
  138. priority P
  139. }
  140. // newPriorityQueue instantiates a new priorityQueueItem.
  141. func newPriorityQueueItem[T any, P constraints.Ordered](value T, priority P) *priorityQueueItem[T, P] {
  142. return &priorityQueueItem[T, P]{
  143. value: value,
  144. priority: priority,
  145. }
  146. }