@@ -24,10 +24,7 @@ would be easier to solve.
2424
2525package queue
2626
27- import (
28- "sort"
29- "sync"
30- )
27+ import "sync"
3128
3229// Item is an item that can be added to the priority queue.
3330type Item interface {
@@ -42,50 +39,66 @@ type Item interface {
4239
4340type priorityItems []Item
4441
42+ func (items * priorityItems ) swap (i , j int ) {
43+ (* items )[i ], (* items )[j ] = (* items )[j ], (* items )[i ]
44+ }
45+
46+ func (items * priorityItems ) pop () Item {
47+ size := len (* items )
48+
49+ // Move last leaf to root, and 'pop' the last item.
50+ items .swap (size - 1 , 0 )
51+ item := (* items )[size - 1 ] // Item to return.
52+ (* items )[size - 1 ], * items = nil , (* items )[:size - 1 ]
53+
54+ // 'Bubble down' to restore heap property.
55+ index := 0
56+ childL , childR := 2 * index + 1 , 2 * index + 2
57+ for len (* items ) > childL {
58+ child := childL
59+ if len (* items ) > childR && (* items )[childR ].Compare ((* items )[childL ]) < 0 {
60+ child = childR
61+ }
62+
63+ if (* items )[child ].Compare ((* items )[index ]) < 0 {
64+ items .swap (index , child )
65+
66+ index = child
67+ childL , childR = 2 * index + 1 , 2 * index + 2
68+ } else {
69+ break
70+ }
71+ }
72+
73+ return item
74+ }
75+
4576func (items * priorityItems ) get (number int ) []Item {
4677 returnItems := make ([]Item , 0 , number )
47- index := 0
4878 for i := 0 ; i < number ; i ++ {
4979 if i >= len (* items ) {
5080 break
5181 }
5282
53- returnItems = append (returnItems , (* items )[i ])
54- (* items )[i ] = nil
55- index ++
83+ returnItems = append (returnItems , items .pop ())
5684 }
5785
58- * items = (* items )[index :]
5986 return returnItems
6087}
6188
62- func (items * priorityItems ) insert (item Item ) {
63- if len (* items ) == 0 {
64- * items = append (* items , item )
65- return
66- }
67-
68- equalFound := false
69- i := sort .Search (len (* items ), func (i int ) bool {
70- result := (* items )[i ].Compare (item )
71- if result == 0 {
72- equalFound = true
73- }
74- return result >= 0
75- })
89+ func (items * priorityItems ) push (item Item ) {
90+ // Stick the item as the end of the last level.
91+ * items = append (* items , item )
7692
77- if equalFound {
78- return
79- }
93+ // 'Bubble up' to restore heap property.
94+ index := len (* items ) - 1
95+ parent := int ((index - 1 ) / 2 )
96+ for parent >= 0 && (* items )[parent ].Compare (item ) > 0 {
97+ items .swap (index , parent )
8098
81- if i == len (* items ) {
82- * items = append (* items , item )
83- return
99+ index = parent
100+ parent = int ((index - 1 ) / 2 )
84101 }
85-
86- * items = append (* items , nil )
87- copy ((* items )[i + 1 :], (* items )[i :])
88- (* items )[i ] = item
89102}
90103
91104// PriorityQueue is similar to queue except that it takes
@@ -94,6 +107,7 @@ func (items *priorityItems) insert(item Item) {
94107type PriorityQueue struct {
95108 waiters waiters
96109 items priorityItems
110+ itemMap map [Item ]struct {}
97111 lock sync.Mutex
98112 disposeLock sync.Mutex
99113 disposed bool
@@ -112,7 +126,10 @@ func (pq *PriorityQueue) Put(items ...Item) error {
112126 }
113127
114128 for _ , item := range items {
115- pq .items .insert (item )
129+ if _ , ok := pq .itemMap [item ]; ! ok {
130+ pq .itemMap [item ] = struct {}{}
131+ pq .items .push (item )
132+ }
116133 }
117134
118135 for {
@@ -150,6 +167,13 @@ func (pq *PriorityQueue) Get(number int) ([]Item, error) {
150167
151168 var items []Item
152169
170+ // Remove references to popped items.
171+ deleteItems := func (items []Item ) {
172+ for _ , item := range items {
173+ delete (pq .itemMap , item )
174+ }
175+ }
176+
153177 if len (pq .items ) == 0 {
154178 sema := newSema ()
155179 pq .waiters .put (sema )
@@ -164,11 +188,13 @@ func (pq *PriorityQueue) Get(number int) ([]Item, error) {
164188 pq .disposeLock .Unlock ()
165189
166190 items = pq .items .get (number )
191+ deleteItems (items )
167192 sema .response .Done ()
168193 return items , nil
169194 }
170195
171196 items = pq .items .get (number )
197+ deleteItems (items )
172198 pq .lock .Unlock ()
173199 return items , nil
174200}
@@ -230,6 +256,7 @@ func (pq *PriorityQueue) Dispose() {
230256// NewPriorityQueue is the constructor for a priority queue.
231257func NewPriorityQueue (hint int ) * PriorityQueue {
232258 return & PriorityQueue {
233- items : make (priorityItems , 0 , hint ),
259+ items : make (priorityItems , 0 , hint ),
260+ itemMap : make (map [Item ]struct {}, hint ),
234261 }
235262}
0 commit comments