github.com/haraldrudell/parl@v0.4.176/pqs/priority-queue.go (about) 1 /* 2 © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 // Ranking is a pointer-identity-to-value map of updatable values traversable by rank. 7 // Ranking implements [parl.Ranking][V comparable, R constraints.Ordered]. 8 package pqs 9 10 import ( 11 "github.com/haraldrudell/parl" 12 "github.com/haraldrudell/parl/parli" 13 "github.com/haraldrudell/parl/perrors" 14 "github.com/haraldrudell/parl/pslices" 15 "golang.org/x/exp/constraints" 16 ) 17 18 // PriorityQueue is a pointer-identity-to-value map of updatable values traversable by rank. 19 // PriorityQueue implements [parl.PriorityQueue][V comparable, R constraints.Ordered]. 20 // - V is a value reference composite type that is comparable, ie. not slice map function. 21 // Preferrably, V is interface or pointer to struct type. 22 // - R is an ordered type such as int floating-point string, used to rank the V values 23 // - values are added or updated using AddOrUpdate method distinguished by 24 // (computer science) identity 25 // - if the same comparable value V is added again, that value is re-ranked 26 // - rank R is computed from a value V using the ranker function. 27 // The ranker function may be examining field values of a struct 28 // - values can have the same rank. If they do, equal rank is provided in insertion order 29 type PriorityQueue[V any, P constraints.Ordered] struct { 30 // priorityFunc is the function computing priority for a value-pointer 31 priorityFunc func(value *V) (priority P) 32 // queue is a list of queue nodes ordered by descending priority 33 queue parli.Ordered[*AssignedPriority[V, P]] 34 // m is a map providing O(1) access to ranking nodes by value-pointer 35 m map[*V]*AssignedPriority[V, P] 36 } 37 38 // NewPriorityQueue returns a map of updatable values traversable by rank 39 func NewPriorityQueue[V any, P constraints.Ordered]( 40 priorityFunc func(value *V) (priority P), 41 ) (priorityQueue parl.PriorityQueue[V, P]) { 42 if priorityFunc == nil { 43 perrors.NewPF("ranker cannot be nil") 44 } 45 r := PriorityQueue[V, P]{ 46 priorityFunc: priorityFunc, 47 m: map[*V]*AssignedPriority[V, P]{}, 48 } 49 r.queue = pslices.NewOrderedAny(r.comparatorFunc) 50 return &r 51 } 52 53 // AddOrUpdate adds a new value to the ranking or updates the ranking of a value 54 // that has changed. 55 func (pq *PriorityQueue[V, P]) AddOrUpdate(valuep *V) { 56 57 // obtain updated priority 58 priority := pq.priorityFunc(valuep) 59 60 var assignedPriority *AssignedPriority[V, P] 61 var ok bool 62 if assignedPriority, ok = pq.m[valuep]; !ok { 63 64 // new value case 65 assignedPriority = NewAssignedPriority(priority, pq.queue.Length(), valuep) 66 pq.m[valuep] = assignedPriority 67 } else { 68 69 // node update case 70 pq.queue.Delete(assignedPriority) 71 assignedPriority.SetPriority(priority) 72 } 73 74 // update order: that’s what we do here. We keep order 75 pq.queue.Insert(assignedPriority) 76 } 77 78 // List returns the first n or default all values by rank 79 func (pq *PriorityQueue[V, P]) List(n ...int) (valueQueue []*V) { 80 81 // get number of items n0 82 var n0 int 83 length := pq.queue.Length() 84 if len(n) > 0 { 85 n0 = n[0] 86 } 87 if n0 < 1 || n0 > length { 88 n0 = length 89 } 90 91 // build list 92 valueQueue = make([]*V, n0) 93 assignedPriorityQueue := pq.queue.List() 94 for i := 0; i < n0; i++ { 95 valueQueue[i] = assignedPriorityQueue[i].Value 96 } 97 return 98 } 99 100 // comparatorFunc is provided to pslices.NewOrderedAny based on AssignedPriority.Cmp 101 func (pq *PriorityQueue[V, P]) comparatorFunc(a, b *AssignedPriority[V, P]) (result int) { 102 return a.Cmp(b) 103 }