-
Notifications
You must be signed in to change notification settings - Fork 0
/
queue.go
96 lines (81 loc) · 2.46 KB
/
queue.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package gwrap
import (
"container/heap"
"golang.org/x/exp/constraints"
)
// PQItemEmbed may be embeded in the priority queue item's data
// structure, or the data structure can have a PQItemEmbed that
// it returns when the PQItem() method is called.
type PQItemEmbed[P constraints.Ordered] struct {
priority P
index int // subtract 1 to get actual index so zero is invalid
}
// PQItem is the interface that items in PriorityQueue must implement.
// Embedding PQItemEmbed is enough to satisfy the interface.
type PQItem[P constraints.Ordered] interface {
PQItem() *PQItemEmbed[P]
}
type innerPriorityQueue[P constraints.Ordered, T PQItem[P]] struct {
slice []T
}
// PriorityQueue is implemented with container/heap and is not thread-safe.
type PriorityQueue[P constraints.Ordered, T PQItem[P]] struct {
i innerPriorityQueue[P, T]
}
// NewPriorityQueue creates a PriorityQueue from a comparison function.
func NewPriorityQueue[P constraints.Ordered, T PQItem[P]]() *PriorityQueue[P, T] {
i := innerPriorityQueue[P, T]{
slice: make([]T, 0, 100),
}
heap.Init(&i)
return &PriorityQueue[P, T]{
i: i,
}
}
func (pqe *PQItemEmbed[P]) PQItem() *PQItemEmbed[P] { return pqe }
func (h *innerPriorityQueue[P, T]) Len() int { return len(h.slice) }
func (h *innerPriorityQueue[P, T]) Less(i, j int) bool {
return h.slice[i].PQItem().priority < h.slice[j].PQItem().priority
}
func (h *innerPriorityQueue[P, T]) Swap(i, j int) {
h.slice[i], h.slice[j] = h.slice[j], h.slice[i]
h.slice[i].PQItem().index = i + 1
h.slice[j].PQItem().index = j + 1
}
// Push is O(log n)
func (h *PriorityQueue[P, T]) Enqueue(x T, priority P) {
if x.PQItem().index != 0 {
panic("cannot add an item to a priority queue if it is already in the queue")
}
x.PQItem().priority = priority
heap.Push(&h.i, x)
}
func (h *innerPriorityQueue[P, T]) Push(x any) {
t := x.(T)
t.PQItem().index = len(h.slice) + 1
h.slice = append(h.slice, t)
}
// Dequeue is O(log n)
func (h *PriorityQueue[P, T]) Dequeue() T {
return heap.Pop(&h.i).(T)
}
func (h *innerPriorityQueue[P, T]) Pop() any {
old := h.slice
n := len(old)
x := old[n-1]
x.PQItem().index = 0
h.slice = old[0 : n-1]
return x
}
func (h PriorityQueue[P, T]) Len() int {
return len(h.i.slice)
}
// Remove takes an item out of the priority queue
func (h *PriorityQueue[P, T]) Remove(x T) {
i := x.PQItem().index
if i == 0 {
panic("cannot remove item from priority queue that is not present in queue")
}
x.PQItem().index = 0
heap.Remove(&h.i, i-1)
}